/*************************************************************************/ /*!
@File
@Title          Common Server PDump functions layer
@Copyright      Copyright (c) Imagination Technologies Ltd. All Rights Reserved
@License        Dual MIT/GPLv2

The contents of this file are subject to the MIT license as set out below.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

Alternatively, the contents of this file may be used under the terms of
the GNU General Public License Version 2 ("GPL") in which case the provisions
of GPL are applicable instead of those above.

If you wish to allow use of your version of this file only under the terms of
GPL, and not to allow others to use your version of this file under the terms
of the MIT license, indicate your decision by deleting the provisions above
and replace them with the notice and other provisions required by GPL as set
out in the file called "GPL-COPYING" included in this distribution. If you do
not delete the provisions above, a recipient may use your version of this file
under the terms of either the MIT license or GPL.

This License is also included in this distribution in the file called
"MIT-COPYING".

EXCEPT AS OTHERWISE STATED IN A NEGOTIATED AGREEMENT: (A) THE SOFTWARE IS
PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT; AND (B) IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/ /**************************************************************************/

#if defined(PDUMP)
#include <stdarg.h>

#include "pvrversion.h"
#include "allocmem.h"
#include "osfunc.h"
#include "pvrsrv.h"
#include "pvr_debug.h"
#include "srvkm.h"
#include "pdump_physmem.h"
#include "hash.h"
#include "connection_server.h"
#include "sync_server.h"
#include "services_km.h"
#include <powervr/buffer_attribs.h>
#include "oskm_apphint.h"

/* pdump headers */
#include "dbgdrvif_srv5.h"
#include "pdump_osfunc.h"
#include "pdump_km.h"
#include <pdumpdesc.h>
#include "rgxpdump.h"

/* Allow temporary buffer size override */
#if !defined(PDUMP_TEMP_BUFFER_SIZE)
#define PDUMP_TEMP_BUFFER_SIZE (64 * 1024U)
#endif

#define	PTR_PLUS(t, p, x) ((t)(((IMG_CHAR *)(p)) + (x)))
#define	VPTR_PLUS(p, x) PTR_PLUS(void *, p, x)
#define	VPTR_INC(p, x) ((p) = VPTR_PLUS(p, x))
#define MAX_PDUMP_MMU_CONTEXTS	(32)
static void *gpvTempBuffer;

#define PRM_FILE_SIZE_MAX	0x7FDFFFFFU /*!< Default maximum file size to split output files, 2GB-2MB as fwrite limits it to 2GB-1 on 32bit systems */


static IMG_BOOL		g_PDumpInitialised = IMG_FALSE;
static IMG_UINT32	g_ConnectionCount;

typedef struct
{
	IMG_UINT32    ui32Init;    /*!< Count of bytes written to the init phase stream */
	IMG_UINT32    ui32Main;    /*!< Count of bytes written to the main stream */
	IMG_UINT32    ui32Deinit;  /*!< Count of bytes written to the deinit stream */
} PDUMP_CHANNEL_WOFFSETS;

typedef struct
{
	PDUMP_CHANNEL          sCh;             /*!< Channel handles */
	PDUMP_CHANNEL_WOFFSETS sWOff;           /*!< Channel file write offsets */
	IMG_UINT32             ui32FileIdx;     /*!< File index increased when each pdump-block finishes in block-mode */
} PDUMP_SCRIPT;

typedef struct
{
	PDUMP_CHANNEL          sCh;             /*!< Channel handles */
	PDUMP_CHANNEL_WOFFSETS sWOff;           /*!< Channel file write offsets */
	IMG_UINT32             ui32FileIdx;     /*!< File index used when file size limit reached and a new file is started, parameter channel only */
	IMG_UINT32             ui32MaxFileSize; /*!< Maximum file size for parameter files */

	PDUMP_FILEOFFSET_T     uiZeroPageOffset; /*!< Offset of the zero page in the parameter file */
	size_t                 uiZeroPageSize;   /*!< Size of the zero page in the parameter file */
	IMG_CHAR               szZeroPageFilename[PDUMP_PARAM_MAX_FILE_NAME]; /*< PRM file name where the zero page was pdumped */
} PDUMP_PARAMETERS;

static PDUMP_SCRIPT     g_PDumpScript    = { { NULL, NULL, NULL}, {0, 0, 0}, 0};
static PDUMP_SCRIPT     g_PDumpBlkScript    = { { NULL, NULL, NULL}, {0, 0, 0}, 0};
static PDUMP_PARAMETERS g_PDumpParameters = { { NULL, NULL, NULL}, {0, 0, 0}, 0, PRM_FILE_SIZE_MAX};


#if defined(PDUMP_DEBUG_OUTFILES)
/* counter increments each time debug write is called */
IMG_UINT32 g_ui32EveryLineCounter = 1U;
#endif

// #define PDUMP_DEBUG_TRANSITION
#if defined(PDUMP_DEBUG_TRANSITION)
# define DEBUG_OUTFILES_COMMENT(fmt, ...) (void)PDumpCommentWithFlags(PDUMP_FLAGS_CONTINUOUS, fmt, __VA_ARGS__)
#else
# define DEBUG_OUTFILES_COMMENT(fmt, ...)
#endif

#if defined(PDUMP_DEBUG) || defined(REFCOUNT_DEBUG)
# define PDUMP_REFCOUNT_PRINT(fmt, ...) PVRSRVDebugPrintf(PVR_DBG_WARNING, __FILE__, __LINE__, fmt, __VA_ARGS__)
#else
# define PDUMP_REFCOUNT_PRINT(fmt, ...)
#endif

/* Prototype for the test/debug state dump routine used in debugging */
void PDumpCommonDumpState(IMG_BOOL bDumpOSLayerState);
#undef PDUMP_TRACE_STATE


/*****************************************************************************/
/*	PDump Control Module Definitions                                         */
/*****************************************************************************/

typedef struct _PDUMP_CAPTURE_RANGE_
{
	IMG_UINT32 ui32Start;       /*!< Start frame number of range, In block-mode of pdump this variable is interpreted differently to keep full-length first block */
	IMG_UINT32 ui32End;         /*!< Send frame number of range, In block-mode of pdump, this variable can be changed by server dynamically on forced capture stop */
	IMG_UINT32 ui32Interval;    /*!< Frame sample rate interval */
} PDUMP_CAPTURE_RANGE;

/* No direct access to members from outside the control module - please */
typedef struct _PDUMP_CTRL_STATE_
{
	IMG_BOOL            bInitPhaseActive;   /*!< State of driver initialisation phase */
	IMG_UINT32          ui32Flags;          /*!< Unused */

	IMG_UINT32          ui32DefaultCapMode; /*!< Capture mode of the dump */
	PDUMP_CAPTURE_RANGE sCaptureRange;      /*!< The capture range for capture mode 'framed' */
	IMG_UINT32          ui32CurrentFrame;   /*!< Current frame number */
	IMG_UINT32          ui32BlockLength;    /*!< PDump block length in terms of number of frames in each pdump-block for capture mode 'block' */
	IMG_UINT32          ui32CurrentBlock;   /*!< Current pdump-block number */

	IMG_BOOL            bCaptureOn;         /*!< Current capture status, is current frame in range */
	IMG_BOOL            bFirstFrameInBlock; /*!< Is current frame first in current pdump-block */
	IMG_BOOL            bSuspended;         /*!< Suspend flag set on unrecoverable error */
	IMG_BOOL            bInPowerTransition; /*!< Device power transition state */
	POS_LOCK            hLock;              /*!< Exclusive lock to this structure */
} PDUMP_CTRL_STATE;

static PDUMP_CTRL_STATE g_PDumpCtrl =
{
	IMG_TRUE,
	0,

	0,                                      /*!< Value obtained from OS PDump layer during initialisation */
	{
		PDUMP_FRAME_UNSET,
		PDUMP_FRAME_UNSET,
		1
	},
	0,
	0,
	PDUMP_BLOCKNUM_INVALID,                 /* Reset value is invalid */

	IMG_FALSE,
	IMG_FALSE,
	IMG_FALSE,
	IMG_FALSE,
	NULL
};

static PVRSRV_ERROR PDumpCtrlInit(IMG_UINT32 ui32InitCapMode)
{
	g_PDumpCtrl.ui32DefaultCapMode = ui32InitCapMode;
	PVR_ASSERT(g_PDumpCtrl.ui32DefaultCapMode != 0);

	/* Create lock for PDUMP_CTRL_STATE struct, which is shared between pdump client
	   and PDumping app. This lock will help us serialize calls from pdump client
	   and PDumping app */
	PVR_LOGR_IF_ERROR(OSLockCreate(&g_PDumpCtrl.hLock), "OSLockCreate");

	return PVRSRV_OK;
}

static void PDumpCtrlDeInit(void)
{
	if (g_PDumpCtrl.hLock)
	{
		OSLockDestroy(g_PDumpCtrl.hLock);
		g_PDumpCtrl.hLock = NULL;
	}
}

static INLINE void PDumpCtrlLockAcquire(void)
{
	OSLockAcquire(g_PDumpCtrl.hLock);
}

static INLINE void PDumpCtrlLockRelease(void)
{
	OSLockRelease(g_PDumpCtrl.hLock);
}

/**********************************************************************************************************
	NOTE:
	The following PDumpCtrl*** functions require the PDUMP_CTRL_STATE lock be acquired BEFORE they are
	called. This is because the PDUMP_CTRL_STATE data is shared between the PDumping App and the PDump
	client, hence an exclusive access is required. The lock can be acquired and released by using the
	PDumpCtrlLockAcquire & PDumpCtrlLockRelease functions respectively.
**********************************************************************************************************/

static void PDumpCtrlUpdateCaptureStatus(void)
{
	if (g_PDumpCtrl.ui32DefaultCapMode == DEBUG_CAPMODE_FRAMED)
	{
		if ((g_PDumpCtrl.ui32CurrentFrame >= g_PDumpCtrl.sCaptureRange.ui32Start) &&
			(g_PDumpCtrl.ui32CurrentFrame <= g_PDumpCtrl.sCaptureRange.ui32End) &&
			(((g_PDumpCtrl.ui32CurrentFrame - g_PDumpCtrl.sCaptureRange.ui32Start) % g_PDumpCtrl.sCaptureRange.ui32Interval) == 0))
		{
			g_PDumpCtrl.bCaptureOn = IMG_TRUE;
		}
		else
		{
			g_PDumpCtrl.bCaptureOn = IMG_FALSE;
		}
	}
	else if ((g_PDumpCtrl.ui32DefaultCapMode == DEBUG_CAPMODE_CONTINUOUS) || (g_PDumpCtrl.ui32DefaultCapMode == DEBUG_CAPMODE_BLKMODE))
	{
		g_PDumpCtrl.bCaptureOn = IMG_TRUE;
	}
	else
	{
		g_PDumpCtrl.bCaptureOn = IMG_FALSE;
		PVR_DPF((PVR_DBG_ERROR, "PDumpCtrlSetCurrentFrame: Unexpected capture mode (%x)", g_PDumpCtrl.ui32DefaultCapMode));
	}

}

static INLINE void PDumpCtrlSuspend(void)
{
	g_PDumpCtrl.bSuspended = IMG_TRUE;
}

static INLINE IMG_BOOL PDumpCtrlIsDumpSuspended(void)
{
	return g_PDumpCtrl.bSuspended;
}

static INLINE IMG_UINT32 PDumpCtrlCapModIsBlkMode(void)
{
	return (g_PDumpCtrl.ui32DefaultCapMode == DEBUG_CAPMODE_BLKMODE);
}

static INLINE IMG_BOOL PDumpCtrlIsCaptureForceStopped(void)
{
	return (PDumpCtrlCapModIsBlkMode() && (g_PDumpCtrl.ui32CurrentFrame > g_PDumpCtrl.sCaptureRange.ui32End));
}

static INLINE IMG_UINT32 PDumpCtrlIsFullLenFirstBlockSet(void)
{
	/* In block-mode of pdump if sCaptureRange.ui32Start is non-zero, set first pdump-block length to full (i.e. ui32BlockLength) */
	return (PDumpCtrlCapModIsBlkMode() && (g_PDumpCtrl.sCaptureRange.ui32Start > 0));
}

/* Set bFirstFrameInBlock in block-mode */
static void PDumpCtrlSetFirstFrameInBlock(IMG_BOOL bFirstFrameInBlock)
{
	g_PDumpCtrl.bFirstFrameInBlock = PDumpCtrlCapModIsBlkMode() && bFirstFrameInBlock;
}

static IMG_BOOL PDumpCtrlIsFirstFrameInBlock(void)
{
	return (PDumpCtrlCapModIsBlkMode() && g_PDumpCtrl.bFirstFrameInBlock);
}

/* This is used to set current pdump-block number, PDUMP_BLOCKNUM_INVALID indicates invalid value */
static void PDumpCtrlSetBlock(IMG_UINT32 ui32BlockNum)
{
	g_PDumpCtrl.ui32CurrentBlock = PDumpCtrlCapModIsBlkMode()? ui32BlockNum : PDUMP_BLOCKNUM_INVALID;
}

static INLINE IMG_UINT32 PDumpCtrlGetBlock(void)
{
	return (PDumpCtrlCapModIsBlkMode()? g_PDumpCtrl.ui32CurrentBlock : PDUMP_BLOCKNUM_INVALID);
}

static PVRSRV_ERROR PDumpCtrlForcedStop(void)
{
	/* In block-mode on forced stop request, capture will be stopped after (current_frame + 1)th frame number.
	 * This ensures that DumpAfterRender always be called on last frame before exiting the PDump capturing
	 */
	g_PDumpCtrl.sCaptureRange.ui32End = g_PDumpCtrl.ui32CurrentFrame + 1;

	PDumpCtrlUpdateCaptureStatus();
	return PVRSRV_OK;
}

static PVRSRV_ERROR _PDumpForceCaptureStopKM(void)
{
	PVRSRV_ERROR eError;

	if(!PDumpCtrlCapModIsBlkMode())
	{
		PVR_DPF((PVR_DBG_ERROR, "%s: This call is valid only in block-mode of PDump i.e. pdump -b<block_frame_len>", __func__));
		return PVRSRV_ERROR_PDUMP_NOT_ALLOWED;
	}

	(void) PDumpCommentWithFlags(PDUMP_FLAGS_CONTINUOUS | PDUMP_FLAGS_BLKDATA, "PDdump STOP capture received at frame %u", g_PDumpCtrl.ui32CurrentFrame);
	PDumpCtrlLockAcquire();
	eError = PDumpCtrlForcedStop();
	PDumpCtrlLockRelease();
	return eError;
}

static void PDumpCtrlUpdateSuspendStatus(void)
{
	if(!PDumpCtrlIsDumpSuspended() && PDumpCtrlIsCaptureForceStopped())
	{
		/* Suspend PDump once received forced capture stop, driver needs restarting to recapture the PDump after this */
		PVR_LOG(("PDump suspended, forced stop capture received."));
		PDumpCtrlSuspend();
	}
}

static void PDumpCtrlSetCurrentFrame(IMG_UINT32 ui32Frame)
{
	g_PDumpCtrl.ui32CurrentFrame = ui32Frame;
	/* Mirror the value into the debug driver */
	PDumpOSSetFrame(ui32Frame);

	PDumpCtrlUpdateCaptureStatus();
	PDumpCtrlUpdateSuspendStatus();

#if defined(PDUMP_TRACE_STATE)
	PDumpCommonDumpState(IMG_FALSE);
#endif
}

static void PDumpCtrlSetDefaultCaptureParams(IMG_UINT32 ui32Mode, IMG_UINT32 ui32Start, IMG_UINT32 ui32End, IMG_UINT32 ui32Interval)
{
	/* Set the capture range to that supplied by the PDump client tool
	 */
	g_PDumpCtrl.ui32DefaultCapMode = ui32Mode;
	g_PDumpCtrl.sCaptureRange.ui32Start = ui32Start;
	g_PDumpCtrl.sCaptureRange.ui32End = ui32End;
	g_PDumpCtrl.sCaptureRange.ui32Interval = ui32Interval;

	g_PDumpCtrl.ui32BlockLength = (ui32Mode == DEBUG_CAPMODE_BLKMODE)?ui32Interval:0;

	/* Reset variables */
	g_PDumpCtrl.ui32CurrentBlock = PDUMP_BLOCKNUM_INVALID;
	g_PDumpCtrl.bFirstFrameInBlock = IMG_FALSE;

	/* Reset the current frame on reset of the capture range, the helps to
	 * avoid inter-pdump start frame issues when the driver is not reloaded.
	 * No need to call PDumpCtrlUpdateCaptureStatus() direct as the set
	 * current frame call will.
	 */
	PDumpCtrlSetCurrentFrame(0);
}

static INLINE IMG_BOOL PDumpCtrlCapModIsFramed(void)
{
	return g_PDumpCtrl.ui32DefaultCapMode == DEBUG_CAPMODE_FRAMED;
}

static INLINE IMG_BOOL PDumpCtrlCapModIsContinuous(void)
{
	return g_PDumpCtrl.ui32DefaultCapMode == DEBUG_CAPMODE_CONTINUOUS;
}

static IMG_UINT32 PDumpCtrlGetCurrentFrame(void)
{
	return g_PDumpCtrl.ui32CurrentFrame;
}

static INLINE IMG_BOOL PDumpCtrlCaptureOn(void)
{
	return !g_PDumpCtrl.bSuspended && g_PDumpCtrl.bCaptureOn;
}

static INLINE IMG_BOOL PDumpCtrlCaptureRangePast(void)
{
	return (g_PDumpCtrl.ui32CurrentFrame > g_PDumpCtrl.sCaptureRange.ui32End);
}

/* Used to imply if the PDump client is connected or not. */
static INLINE IMG_BOOL PDumpCtrlCaptureRangeUnset(void)
{
	return ((g_PDumpCtrl.sCaptureRange.ui32Start == PDUMP_FRAME_UNSET) &&
			(g_PDumpCtrl.sCaptureRange.ui32End == PDUMP_FRAME_UNSET));
}

static IMG_BOOL PDumpCtrlIsLastCaptureFrame(void)
{
	if (g_PDumpCtrl.ui32DefaultCapMode == DEBUG_CAPMODE_FRAMED)
	{
		/* Is the next capture frame within the range end limit? */
		if ((g_PDumpCtrl.ui32CurrentFrame + g_PDumpCtrl.sCaptureRange.ui32Interval) > g_PDumpCtrl.sCaptureRange.ui32End)
		{
			return IMG_TRUE;
		}
	}
	else if(PDumpCtrlCapModIsBlkMode())
	{
		/* Is the next capture frame within the range end limit? (end limit will be modified on forced capture stop in block-mode) */
		if((g_PDumpCtrl.ui32CurrentFrame  + 1) > g_PDumpCtrl.sCaptureRange.ui32End)
		{
			return IMG_TRUE;
		}
	}
	else
	{
		PVR_DPF((PVR_DBG_ERROR, "PDumpCtrIsLastCaptureFrame: Unexpected capture mode (%x)", g_PDumpCtrl.ui32DefaultCapMode));
	}

	/* Return false for continuous capture mode or when in framed mode */
	return IMG_FALSE;
}

static INLINE IMG_BOOL PDumpCtrlInitPhaseComplete(void)
{
	return !g_PDumpCtrl.bInitPhaseActive;
}

static INLINE void PDumpCtrlSetInitPhaseComplete(IMG_BOOL bIsComplete)
{
	if (bIsComplete)
	{
		g_PDumpCtrl.bInitPhaseActive = IMG_FALSE;
		PDUMP_HEREA(102);
	}
	else
	{
		g_PDumpCtrl.bInitPhaseActive = IMG_TRUE;
		PDUMP_HEREA(103);
	}
}

static INLINE void PDumpCtrlPowerTransitionStart(void)
{
	g_PDumpCtrl.bInPowerTransition = IMG_TRUE;
}

static INLINE void PDumpCtrlPowerTransitionEnd(void)
{
	g_PDumpCtrl.bInPowerTransition = IMG_FALSE;
}

static INLINE IMG_BOOL PDumpCtrlInPowerTransition(void)
{
	return g_PDumpCtrl.bInPowerTransition;
}

static PVRSRV_ERROR PDumpCtrlGetState(IMG_UINT64 *ui64State)
{
	*ui64State = 0;
	if(PDumpCtrlCaptureOn())
	{
		*ui64State |= PDUMP_STATE_CAPTURE_FRAME;
	}

	if(!PDumpCtrlCaptureRangeUnset() && PDumpCtrlInitPhaseComplete())
	{
		*ui64State |= PDUMP_STATE_CONNECTED;
	}

	return PVRSRV_OK;
}

/********************************************************************************
	End of PDumpCtrl*** functions
*********************************************************************************/

/*
	Wrapper functions which need to be exposed in pdump_km.h for use in other
	pdump_*** modules safely. These functions call the specific PDumpCtrl layer
	function after acquiring the PDUMP_CTRL_STATE lock, hence making the calls
	from other modules hassle free by avoiding the acquire/release CtrlLock
	calls.
*/

void PDumpPowerTransitionStart(void)
{
	PDumpCtrlLockAcquire();
	PDumpCtrlPowerTransitionStart();
	PDumpCtrlLockRelease();
}

void PDumpPowerTransitionEnd(void)
{
	PDumpCtrlLockAcquire();
	PDumpCtrlPowerTransitionEnd();
	PDumpCtrlLockRelease();
}

IMG_BOOL PDumpInPowerTransition(void)
{
	IMG_BOOL bPDumpInPowerTransition = IMG_FALSE;

	PDumpCtrlLockAcquire();
	bPDumpInPowerTransition = PDumpCtrlInPowerTransition();
	PDumpCtrlLockRelease();

	return bPDumpInPowerTransition;
}

IMG_BOOL PDumpIsDumpSuspended(void)
{
	IMG_BOOL bPDumpIsDumpSuspended;

	PDumpCtrlLockAcquire();
	bPDumpIsDumpSuspended = PDumpCtrlIsDumpSuspended();
	PDumpCtrlLockRelease();

	return bPDumpIsDumpSuspended;
}

/*****************************************************************************/
/*	PDump Common Write Layer just above PDump OS Layer                       */
/*****************************************************************************/


/*
	Checks in this method were seeded from the original PDumpWriteILock()
	and DBGDrivWriteCM() and have grown since to ensure PDump output
	matches legacy output.
	Note: the order of the checks in this method is important as some
	writes have multiple pdump flags set!
 */
static IMG_BOOL PDumpWriteAllowed(IMG_UINT32 ui32Flags)
{
	/* Lock down the PDUMP_CTRL_STATE struct before calling the following
	   PDumpCtrl*** functions. This is to avoid updates to the Control data
	   while we are reading from it */
	PDumpCtrlLockAcquire();

	/* No writes if in framed mode and range pasted */
	if (PDumpCtrlCaptureRangePast())
	{
		PDUMP_HERE(10);
		goto unlockAndReturnFalse;
	}

	/* No writes while writing is suspended */
	if (PDumpCtrlIsDumpSuspended())
	{
		PDUMP_HERE(11);
		goto unlockAndReturnFalse;
	}

	/* Prevent PDumping during a power transition */
	if (PDumpCtrlInPowerTransition())
	{	/* except when it's flagged */
		if (ui32Flags & PDUMP_FLAGS_POWER)
		{
			PDUMP_HERE(20);
			goto unlockAndReturnTrue;
		}
		PDUMP_HERE(16);
		goto unlockAndReturnFalse;
	}

	/* Always allow dumping in init phase and when persistent flagged */
	if (ui32Flags & PDUMP_FLAGS_PERSISTENT)
	{
		PDUMP_HERE(12);
		goto unlockAndReturnTrue;
	}
	if (!PDumpCtrlInitPhaseComplete())
	{
		PDUMP_HERE(15);
		goto unlockAndReturnTrue;
	}

	/* The following checks are made when the driver has completed initialisation */

	/* If PDump client connected allow continuous flagged writes */
	if (PDUMP_IS_CONTINUOUS(ui32Flags))
	{
		if (PDumpCtrlCaptureRangeUnset()) /* Is client connected? */
		{
			PDUMP_HERE(13);
			goto unlockAndReturnFalse;
		}
		PDUMP_HERE(14);
		goto unlockAndReturnTrue;
	}

	/* No last/deinit statements allowed when not in initialisation phase */
	if (PDUMP_IS_CONTINUOUS(ui32Flags))
	{
		if (PDumpCtrlInitPhaseComplete())
		{
			PDUMP_HERE(17);
			PVR_DPF((PVR_DBG_ERROR, "PDumpWriteAllowed: DEINIT flag used at the wrong time outside of initialisation!"));
			goto unlockAndReturnFalse;
		}
	}

	/*
		If no flags are provided then it is FRAMED output and the frame
		range must be checked matching expected behaviour.
	 */
	if (PDumpCtrlCapModIsFramed() && !PDumpCtrlCaptureOn())
	{
		PDUMP_HERE(18);
		goto unlockAndReturnFalse;
	}

	PDUMP_HERE(19);

unlockAndReturnTrue:
	/* Allow the write to take place */
	PDumpCtrlLockRelease();
	return IMG_TRUE;

unlockAndReturnFalse:
	PDumpCtrlLockRelease();
	return IMG_FALSE;
}

#undef PDUMP_DEBUG_SCRIPT_LINES

#if defined(PDUMP_DEBUG_SCRIPT_LINES)
#define PDUMPOSDEBUGDRIVERWRITE(a,b,c,d) _PDumpOSDebugDriverWrite(a,b,c,d)
static IMG_UINT32 _PDumpOSDebugDriverWrite( IMG_HANDLE psStream,
									IMG_UINT8 *pui8Data,
									IMG_UINT32 ui32BCount,
									IMG_UINT32 ui32Flags)
{
	IMG_CHAR tmp1[80];
	IMG_CHAR* streamName = "unkn";

	if (g_PDumpScript.sCh.hDeinit == psStream)
		streamName = "dein";
	else if (g_PDumpScript.sCh.hInit == psStream)
		streamName = "init";
	else if (g_PDumpScript.sCh.hMain == psStream)
		streamName = "main";

	(void) PDumpOSSprintf(tmp1, 80, "-- %s, %x\n", streamName, ui32Flags);
	(void) PDumpOSDebugDriverWrite(psStream, tmp1, OSStringLength(tmp1));

	return PDumpOSDebugDriverWrite(psStream, pui8Data, ui32BCount);
}
#else
#define PDUMPOSDEBUGDRIVERWRITE(a,b,c,d) PDumpOSDebugDriverWrite(a,b,c)
#endif


/**************************************************************************/ /*!
 @Function		PDumpWriteToBuffer
 @Description	Write the supplied data to the PDump stream buffer and attempt
                to handle any buffer full conditions to ensure all the data
                requested to be written, is.

 @Input			psStream	The address of the PDump stream buffer to write to
 @Input			pui8Data    Pointer to the data to be written
 @Input			ui32BCount	Number of bytes to write
 @Input			ui32Flags	PDump statement flags.

 @Return 		IMG_UINT32  Actual number of bytes written, may be less than
 	 	 	 	 	 	 	ui32BCount when buffer full condition could not
 	 	 	 	 	 	 	be avoided.
*/ /***************************************************************************/
static IMG_UINT32 PDumpWriteToBuffer(IMG_HANDLE psStream, IMG_UINT8 *pui8Data,
		IMG_UINT32 ui32BCount, IMG_UINT32 ui32Flags)
{
	IMG_UINT32	ui32BytesWritten = 0;
	IMG_UINT32	ui32Off = 0;

	while (ui32BCount > 0)
	{
		ui32BytesWritten = PDUMPOSDEBUGDRIVERWRITE(psStream, &pui8Data[ui32Off], ui32BCount, ui32Flags);

		if (ui32BytesWritten == 0)
		{
			PVR_DPF((PVR_DBG_MESSAGE, "PDumpWriteToBuffer: Zero bytes written - release execution"));
			PDumpOSReleaseExecution();
		}

		if (ui32BytesWritten != 0xFFFFFFFFU)
		{
			if (ui32BCount != ui32BytesWritten)
			{
				PVR_DPF((PVR_DBG_MESSAGE, "PDumpWriteToBuffer: partial write of %d bytes of %d bytes", ui32BytesWritten, ui32BCount));
			}
			ui32Off += ui32BytesWritten;
			ui32BCount -= ui32BytesWritten;
		}
		else
		{
			PVR_DPF((PVR_DBG_ERROR, "PDumpWriteToBuffer: Unrecoverable error received from the debug driver"));
			if( PDumpOSGetCtrlState(psStream, DBG_GET_STATE_FLAG_IS_READONLY) )
			{
				/* Fatal -suspend PDump to prevent flooding kernel log buffer */
				PVR_LOG(("PDump suspended, debug driver out of memory"));
				/*
					Acquire the control lock before updating "suspended" state. This may not be required
					because "this" is the context which checks the "suspended" state in PDumpWriteAllowed
					before calling this function. So, this update is mainly for other contexts.
					Also, all the other contexts which will/wish-to read the "suspended" state ought to be
					waiting on the bridge lock first and then the PDUMP_OSLOCK (to pdump into script or
					parameter buffer). However, this acquire may be useful in case the PDump call is being
					made from a direct bridge
				*/
				PDumpCtrlLockAcquire();
				PDumpCtrlSuspend();
				PDumpCtrlLockRelease();
			}
			return 0;
		}
	}

	/* reset buffer counters */
	ui32BCount = ui32Off; ui32Off = 0; ui32BytesWritten = 0;

	return ui32BCount;
}


/**************************************************************************/ /*!
 @Function		PDumpWriteToChannel
 @Description	Write the supplied data to the PDump channel specified obeying
 	            flags to write to the necessary channel buffers.

 @Input			psChannel	The address of the script or parameter channel object
 @Input/Output	psWOff		The address of the channel write offsets object to
                            update on successful writing
 @Input			pui8Data    Pointer to the data to be written
 @Input			ui32Size	Number of bytes to write
 @Input			ui32Flags	PDump statement flags, they may be clear (no flags)
                            which implies framed data, continuous flagged,
                            persistent flagged, or continuous AND persistent
                            flagged and they determine how the data is output.
                            On the first test app run after driver load, the
                            Display Controller dumps a resource that is both
                            continuous and persistent and this needs writing to
                            both the init (persistent) and main (continuous)
                            channel buffers to ensure the data is dumped in
                            subsequent test runs without reloading the driver.
    						In subsequent runs the PDump client 'freezes' the
    						init buffer so that only one dump of persistent data
    						for the "extended init phase" is captured to the
    						init buffer.

 @Return 		IMG_BOOL    True when the data has been consumed, false otherwise
*/ /***************************************************************************/
static IMG_BOOL PDumpWriteToChannel(PDUMP_CHANNEL* psChannel, PDUMP_CHANNEL_WOFFSETS* psWOff,
		IMG_UINT8* pui8Data, IMG_UINT32 ui32Size, IMG_UINT32 ui32Flags)
{
	IMG_UINT32   ui32BytesWritten = 0;

	PDUMP_HERE(210);

	/* Dump data to deinit buffer when flagged as deinit */
	if (ui32Flags & PDUMP_FLAGS_DEINIT)
	{
		PDUMP_HERE(211);
		ui32BytesWritten = PDumpWriteToBuffer(psChannel->hDeinit, pui8Data, ui32Size, ui32Flags);
		if (ui32BytesWritten != ui32Size)
		{
			PVR_DPF((PVR_DBG_ERROR, "PDumpWriteToChannel: DEINIT Written length (%d) does not match data length (%d), PDump incomplete!", ui32BytesWritten, ui32Size));
			PDUMP_HERE(212);
			return IMG_FALSE;
		}

		if (psWOff)
		{
			psWOff->ui32Deinit += ui32Size;
		}

	}
	else
	{
		IMG_BOOL bDumpedToInitAlready = IMG_FALSE;
		IMG_HANDLE*  phStream = NULL;
		IMG_UINT32*  pui32Offset = NULL;

		/* Always append persistent data to init phase so it's available on
		 * subsequent app runs, but also to the main stream if client connected */
		if (ui32Flags & PDUMP_FLAGS_PERSISTENT)
		{
			PDUMP_HERE(213);
			ui32BytesWritten = PDumpWriteToBuffer(	psChannel->hInit, pui8Data, ui32Size, ui32Flags);
			if (ui32BytesWritten != ui32Size)
			{
				PVR_DPF((PVR_DBG_ERROR, "PDumpWriteToChannel: PERSIST Written length (%d) does not match data length (%d), PDump incomplete!", ui32BytesWritten, ui32Size));
				PDUMP_HERE(214);
				return IMG_FALSE;
			}

			bDumpedToInitAlready = IMG_TRUE;
			if (psWOff)
			{
				psWOff->ui32Init += ui32Size;
			}

			/* Don't write continuous data if client not connected */
			PDumpCtrlLockAcquire();
			if (PDumpCtrlCaptureRangeUnset())
			{
				PDumpCtrlLockRelease();
				return IMG_TRUE;
			}
			PDumpCtrlLockRelease();
		}

		/* Prepare to write the data to the main stream for
		 * persistent, continuous or framed data. Override and use init
		 * stream if driver still in init phase and we have not written
		 * to it yet.*/
		PDumpCtrlLockAcquire();
		if (!PDumpCtrlInitPhaseComplete() && !bDumpedToInitAlready)
		{
			PDUMP_HERE(215);
			phStream = &psChannel->hInit;
			if (psWOff)
			{
				pui32Offset = &psWOff->ui32Init;
			}
		}
		else
		{
			PDUMP_HERE(216);
			phStream = &psChannel->hMain;
			if (psWOff)
			{
				pui32Offset = &psWOff->ui32Main;
			}
		}
		PDumpCtrlLockRelease();

		/* Write the data to the stream */
		ui32BytesWritten = PDumpWriteToBuffer(*phStream, pui8Data, ui32Size, ui32Flags);
		if (ui32BytesWritten != ui32Size)
		{
			PVR_DPF((PVR_DBG_ERROR, "PDumpWriteToChannel: MAIN Written length (%d) does not match data length (%d), PDump incomplete!", ui32BytesWritten, ui32Size));
			PDUMP_HERE(217);
			return IMG_FALSE;
		}

		if (pui32Offset)
		{
			*pui32Offset += ui32BytesWritten;
		}
	}

	return IMG_TRUE;
}

#if defined(PDUMP_DEBUG_OUTFILES)

static IMG_UINT32 _GenerateChecksum(void *pvData, size_t uiSize)
{
	IMG_UINT32 ui32Sum = 0;
	IMG_UINT32 *pui32Data = pvData;
	IMG_UINT8 *pui8Data = pvData;
	IMG_UINT32 i;
	IMG_UINT32 ui32LeftOver;

	for(i = 0; i < uiSize / sizeof(IMG_UINT32); i++)
	{
		ui32Sum += pui32Data[i];
	}

	ui32LeftOver = uiSize % sizeof(IMG_UINT32);

	while(ui32LeftOver)
	{
		ui32Sum += pui8Data[uiSize - ui32LeftOver];
		ui32LeftOver--;
	}

	return ui32Sum;
}

#endif

PVRSRV_ERROR PDumpWriteParameter(IMG_UINT8 *pui8Data, IMG_UINT32 ui32Size, IMG_UINT32 ui32Flags,
		IMG_UINT32* pui32FileOffset, IMG_CHAR* aszFilenameStr)
{
	PVRSRV_ERROR eError = PVRSRV_OK;
	IMG_BOOL bPDumpCtrlInitPhaseComplete = IMG_FALSE;

	PVR_ASSERT(pui8Data && (ui32Size!=0));
	PVR_ASSERT(pui32FileOffset && aszFilenameStr);

	PDUMP_HERE(1);

	if (!PDumpWriteAllowed(ui32Flags))
	{
		/* Abort write for the above reason but indicate what happened to
		 * caller to avoid disrupting the driver, caller should treat it as OK
		 * but skip any related PDump writes to the script file.  */
		return PVRSRV_ERROR_PDUMP_NOT_ALLOWED;
	}

	PDUMP_HERE(2);

	PDumpCtrlLockAcquire();
	bPDumpCtrlInitPhaseComplete = PDumpCtrlInitPhaseComplete();
	PDumpCtrlLockRelease();

	if (!bPDumpCtrlInitPhaseComplete || (ui32Flags & PDUMP_FLAGS_PERSISTENT))
	{
		PDUMP_HERE(3);

		/* Init phase stream not expected to get above the file size max */
		PVR_ASSERT(g_PDumpParameters.sWOff.ui32Init < g_PDumpParameters.ui32MaxFileSize);

		/* Return the file write offset at which the parameter data was dumped */
		*pui32FileOffset = g_PDumpParameters.sWOff.ui32Init;
	}
	else
	{
		PDUMP_HERE(4);

		/* Do we need to signal the PDump client that a split is required? */
		if (g_PDumpParameters.sWOff.ui32Main + ui32Size > g_PDumpParameters.ui32MaxFileSize)
		{
			PDUMP_HERE(5);
			PDumpOSSetSplitMarker(g_PDumpParameters.sCh.hMain, g_PDumpParameters.sWOff.ui32Main);
			g_PDumpParameters.ui32FileIdx++;
			g_PDumpParameters.sWOff.ui32Main = 0;
		}

		/* Return the file write offset at which the parameter data was dumped */
		*pui32FileOffset = g_PDumpParameters.sWOff.ui32Main;
	}

	/* Create the parameter file name, based on index, to be used in the script */
	if (g_PDumpParameters.ui32FileIdx == 0)
	{
		eError = PDumpOSSprintf(aszFilenameStr, PDUMP_PARAM_MAX_FILE_NAME, PDUMP_PARAM_0_FILE_NAME);
	}
	else
	{
		PDUMP_HERE(6);
		eError = PDumpOSSprintf(aszFilenameStr, PDUMP_PARAM_MAX_FILE_NAME, PDUMP_PARAM_N_FILE_NAME, g_PDumpParameters.ui32FileIdx);
	}
	PVR_LOGG_IF_ERROR(eError, "PDumpOSSprintf", errExit);

	/* Write the parameter data to the parameter channel */
	eError = PVRSRV_ERROR_PDUMP_BUFFER_FULL;
	if (!PDumpWriteToChannel(&g_PDumpParameters.sCh, &g_PDumpParameters.sWOff, pui8Data, ui32Size, ui32Flags))
	{
		PDUMP_HERE(7);
		PVR_LOGG_IF_ERROR(eError, "PDumpWrite", errExit);
	}
#if defined(PDUMP_DEBUG_OUTFILES)
	else
	{
		IMG_UINT32 ui32Checksum;
		PDUMP_GET_SCRIPT_STRING();

		ui32Checksum = _GenerateChecksum(pui8Data, ui32Size);

		/* CHK CHKSUM SIZE PRMOFFSET PRMFILE */
		eError = PDumpOSBufprintf(hScript, ui32MaxLen, "-- CHK 0x%08X 0x%08X 0x%08X %s",
									ui32Checksum,
									ui32Size,
									*pui32FileOffset,
									aszFilenameStr);
		if(eError != PVRSRV_OK)
		{
			goto errExit;
		}

		PDumpWriteScript(hScript, ui32Flags);
	}
#endif

	return PVRSRV_OK;

errExit:
	return eError;
}


IMG_BOOL PDumpWriteScript(IMG_HANDLE hString, IMG_UINT32 ui32Flags)
{
	PVR_ASSERT(hString);

	PDUMP_HERE(201);

	if (!PDumpWriteAllowed(ui32Flags))
	{
		/* Abort write for the above reasons but indicated it was OK to
		 * caller to avoid disrupting the driver */
		return IMG_TRUE;
	}

	if (PDumpCtrlCapModIsBlkMode())
	{
 		if(ui32Flags & PDUMP_FLAGS_FORCESPLIT)
		{
			/* Split Block script stream */
			PVR_DPF((PVR_DBG_MESSAGE,"[g_PDumpBlkScript] Splitting stream with Marker set to %d, ui32FileIdx %d", g_PDumpBlkScript.sWOff.ui32Main, g_PDumpBlkScript.ui32FileIdx));

			while(PDumpOSGetSplitMarker(g_PDumpBlkScript.sCh.hMain)){}; /* Let the pdump client process last split requested before splitting again */
			PDumpOSSetSplitMarker(g_PDumpBlkScript.sCh.hMain, g_PDumpBlkScript.sWOff.ui32Main);
			g_PDumpBlkScript.ui32FileIdx++;
			g_PDumpBlkScript.sWOff.ui32Main = 0;


			/* Split main script stream */
			PVR_DPF((PVR_DBG_MESSAGE,"[g_PDumpScript] Splitting stream with Marker set to %d, ui32FileIdx %d", g_PDumpScript.sWOff.ui32Main, g_PDumpScript.ui32FileIdx));

			while(PDumpOSGetSplitMarker(g_PDumpScript.sCh.hMain)){}; /* Let the pdump client process last split requested before splitting again */
			PDumpOSSetSplitMarker(g_PDumpScript.sCh.hMain, g_PDumpScript.sWOff.ui32Main);
			g_PDumpScript.ui32FileIdx++;
			g_PDumpScript.sWOff.ui32Main = 0;
		}

		if(ui32Flags & PDUMP_FLAGS_BLKDATA)
		{
			/* Write data to block stream if PDUMP_FLAGS_BLKDATA flag is set */
			if(!PDumpWriteToChannel(&g_PDumpBlkScript.sCh, &g_PDumpBlkScript.sWOff, (IMG_UINT8*) hString, (IMG_UINT32) OSStringLength((IMG_CHAR*) hString), ui32Flags))
			{
				return IMG_FALSE;
			}
		}
	}

	return PDumpWriteToChannel(&g_PDumpScript.sCh, &g_PDumpScript.sWOff, (IMG_UINT8*) hString, (IMG_UINT32) OSStringLength((IMG_CHAR*) hString), ui32Flags);
}


/*****************************************************************************/






struct _PDUMP_CONNECTION_DATA_ {
	ATOMIC_T				sRefCount;
	POS_LOCK				hLock; /*!< Protects access to sListHead. */
	DLLIST_NODE				sListHead;
	IMG_BOOL				bLastInto;
	IMG_UINT32				ui32LastSetFrameNumber;
	IMG_BOOL				bWasInCaptureRange;
	IMG_BOOL				bIsInCaptureRange;
	IMG_BOOL				bLastTransitionFailed;
	SYNC_CONNECTION_DATA	*psSyncConnectionData;
};

static PDUMP_CONNECTION_DATA * _PDumpConnectionAcquire(PDUMP_CONNECTION_DATA *psPDumpConnectionData)
{
	IMG_INT iRefCount = OSAtomicIncrement(&psPDumpConnectionData->sRefCount);

	PDUMP_REFCOUNT_PRINT("%s: PDump connection %p, refcount = %d", __func__,
	                     psPDumpConnectionData, iRefCount);
	PVR_UNREFERENCED_PARAMETER(iRefCount);

	return psPDumpConnectionData;
}

static void _PDumpConnectionRelease(PDUMP_CONNECTION_DATA *psPDumpConnectionData)
{
	IMG_INT iRefCount = OSAtomicDecrement(&psPDumpConnectionData->sRefCount);
	if (iRefCount == 0)
	{
		OSLockDestroy(psPDumpConnectionData->hLock);
		PVR_ASSERT(dllist_is_empty(&psPDumpConnectionData->sListHead));
		OSFreeMem(psPDumpConnectionData);
	}

	PDUMP_REFCOUNT_PRINT("%s: PDump connection %p, refcount = %d", __func__,
	                     psPDumpConnectionData, iRefCount);
}

/**************************************************************************
 * Function Name  : GetTempBuffer
 * Inputs         : None
 * Outputs        : None
 * Returns        : Temporary buffer address, or NULL
 * Description    : Get temporary buffer address.
**************************************************************************/
static void *GetTempBuffer(void)
{
	/*
	 * Allocate the temporary buffer, if it hasn't been allocated already.
	 * Return the address of the temporary buffer, or NULL if it
	 * couldn't be allocated.
	 * It is expected that the buffer will be allocated once, at driver
	 * load time, and left in place until the driver unloads.
	 */

	if (gpvTempBuffer == NULL)
	{
		gpvTempBuffer = OSAllocMem(PDUMP_TEMP_BUFFER_SIZE);
		if (gpvTempBuffer == NULL)
		{
			PVR_DPF((PVR_DBG_ERROR, "GetTempBuffer: OSAllocMem failed"));
		}
	}

	return gpvTempBuffer;
}

static void FreeTempBuffer(void)
{

	if (gpvTempBuffer != NULL)
	{
		OSFreeMem(gpvTempBuffer);
		gpvTempBuffer = NULL;
	}
}

/**************************************************************************
 * Function Name  : PDumpParameterChannelZeroedPageBlock
 * Inputs         : None
 * Outputs        : None
 * Returns        : PVRSRV_ERROR
 * Description    : Set up the zero page block in the parameter stream
**************************************************************************/
static PVRSRV_ERROR PDumpParameterChannelZeroedPageBlock(void)
{
	IMG_UINT8 aui8Zero[32] = { 0 };
	size_t uiBytesToWrite;
	PVRSRV_ERROR eError;
	void *pvAppHintState = NULL;
	IMG_UINT32 ui32AppHintDefault = PVRSRV_APPHINT_GENERAL_NON4K_HEAP_PAGE_SIZE;
	IMG_UINT32 ui32GeneralNon4KHeapPageSize;

	OSCreateKMAppHintState(&pvAppHintState);
	OSGetKMAppHintUINT32(pvAppHintState, GeneralNon4KHeapPageSize,
			&ui32AppHintDefault, &ui32GeneralNon4KHeapPageSize);
	OSFreeKMAppHintState(pvAppHintState);

	/* ZeroPageSize can't be smaller than page size */
	g_PDumpParameters.uiZeroPageSize = MAX(ui32GeneralNon4KHeapPageSize, OSGetPageSize());

	/* ensure the zero page size of a multiple of the zero source on the stack */
	PVR_ASSERT(g_PDumpParameters.uiZeroPageSize % sizeof(aui8Zero) == 0);

	/* the first write gets the parameter file name and stream offset,
	 * then subsequent writes do not need to know this as the data is
	 * contiguous in the stream
	 */
	PDUMP_LOCK();
	eError = PDumpWriteParameter(aui8Zero,
							sizeof(aui8Zero),
							0,
							&g_PDumpParameters.uiZeroPageOffset,
							g_PDumpParameters.szZeroPageFilename);

	if(eError != PVRSRV_OK)
	{
		/* Also treat PVRSRV_ERROR_PDUMP_NOT_ALLOWED as an error in this case
		 * as it should never happen since all writes during driver Init are allowed.
		 */
		goto err_write;
	}

	uiBytesToWrite = g_PDumpParameters.uiZeroPageSize - sizeof(aui8Zero);

	while(uiBytesToWrite)
	{
		IMG_BOOL bOK;

		bOK = PDumpWriteToChannel(&g_PDumpParameters.sCh, &g_PDumpParameters.sWOff,
									aui8Zero,
									sizeof(aui8Zero), 0);

		if(!bOK)
		{
			eError = PVRSRV_ERROR_PDUMP_BUFFER_FULL;
			goto err_write;
		}

		uiBytesToWrite -= sizeof(aui8Zero);
	}

err_write:
	PDUMP_UNLOCK();

	if(eError != PVRSRV_OK)
	{
		PVR_DPF((PVR_DBG_ERROR, "Failed to initialise parameter stream zero block"));
	}

	return eError;
}

/**************************************************************************
 * Function Name  : PDumpGetParameterZeroPageInfo
 * Inputs         : None
 * Outputs        : puiZeroPageOffset: will be set to the offset of the zero page
 *                : puiZeroPageSize: will be set to the size of the zero page
 *                : ppszZeroPageFilename: will be set to a pointer to the PRM file name
 *                :                       containing the zero page
 * Returns        : None
 * Description    : Get information about the zero page
**************************************************************************/
void PDumpGetParameterZeroPageInfo(PDUMP_FILEOFFSET_T *puiZeroPageOffset,
					size_t *puiZeroPageSize,
					const IMG_CHAR **ppszZeroPageFilename)
{
		*puiZeroPageOffset = g_PDumpParameters.uiZeroPageOffset;
		*puiZeroPageSize = g_PDumpParameters.uiZeroPageSize;
		*ppszZeroPageFilename = g_PDumpParameters.szZeroPageFilename;
}

PVRSRV_ERROR PDumpInitCommon(void)
{
	PVRSRV_ERROR eError;
	IMG_UINT32 ui32InitCapMode = 0;
	IMG_CHAR* pszEnvComment = NULL;

	PDUMP_HEREA(2010);

	/* Allocate temporary buffer for copying from user space */
	(void) GetTempBuffer();

	/* create the global PDump lock */
	eError = PDumpCreateLockKM();
	PVR_LOGG_IF_ERROR(eError, "PDumpCreateLockKM", errExit);

	/* Call environment specific PDump initialisation */
	eError = PDumpOSInit(&g_PDumpParameters.sCh, &g_PDumpScript.sCh, &g_PDumpBlkScript.sCh, &ui32InitCapMode, &pszEnvComment);
	PVR_LOGG_IF_ERROR(eError, "PDumpOSInit", errExitLock);

	/* Initialise PDump control module in common layer */
	eError = PDumpCtrlInit(ui32InitCapMode);
	PVR_LOGG_IF_ERROR(eError, "PDumpCtrlInit", errExitOSDeInit);

	/* Test PDump initialised and ready by logging driver details */
	eError = PDumpCommentWithFlags(PDUMP_FLAGS_CONTINUOUS, "Driver Product Version: %s - %s (%s)", PVRVERSION_STRING, PVR_BUILD_DIR, PVR_BUILD_TYPE);
	PVR_LOGG_IF_ERROR(eError, "PDumpCommentWithFlags", errExitCtrl);
	if (pszEnvComment != NULL)
	{
		eError = PDumpCommentWithFlags(PDUMP_FLAGS_CONTINUOUS, "%s", pszEnvComment);
		PVR_LOGG_IF_ERROR(eError, "PDumpCommentWithFlags", errExitCtrl);
	}
	eError = PDumpCommentWithFlags(PDUMP_FLAGS_CONTINUOUS, "Start of Init Phase");
	PVR_LOGG_IF_ERROR(eError, "PDumpCommentWithFlags", errExitCtrl);

	eError = PDumpParameterChannelZeroedPageBlock();
	PVR_LOGG_IF_ERROR(eError, "PDumpParameterChannelZeroedPageBlock", errExitCtrl);

	g_PDumpInitialised = IMG_TRUE;

	PDUMP_HEREA(2011);

	return PVRSRV_OK;

errExitCtrl:
	PDumpCtrlDeInit();
errExitOSDeInit:
	PDUMP_HEREA(2018);
	PDumpOSDeInit(&g_PDumpParameters.sCh, &g_PDumpScript.sCh, &g_PDumpBlkScript.sCh);
errExitLock:
	PDUMP_HEREA(2019);
	PDumpDestroyLockKM();
errExit:
	return eError;
}

void PDumpDeInitCommon(void)
{
	PDUMP_HEREA(2020);

	g_PDumpInitialised = IMG_FALSE;

	/* Free temporary buffer */
	FreeTempBuffer();

	/* DeInit the PDUMP_CTRL_STATE data */
	PDumpCtrlDeInit();

	/* Call environment specific PDump Deinitialisation */
	PDumpOSDeInit(&g_PDumpParameters.sCh, &g_PDumpScript.sCh, &g_PDumpBlkScript.sCh);

	/* take down the global PDump lock */
	PDumpDestroyLockKM();
}

IMG_BOOL PDumpReady(void)
{
	return g_PDumpInitialised;
}

void PDumpStopInitPhase(IMG_BOOL bPDumpClient, IMG_BOOL bInitClient)
{
	/* Check with the OS we a running on */
	if (PDumpOSAllowInitPhaseToComplete(bPDumpClient, bInitClient))
	{
		if (bInitClient)
		{
			/* We only ouptut this once for bInitClient init phase ending OSs */
			PDUMPCOMMENT("Stop Init Phase");
		}
		PDumpCtrlLockAcquire();
		PDumpCtrlSetInitPhaseComplete(IMG_TRUE);
		PDumpCtrlLockRelease();
	}
}

PVRSRV_ERROR PDumpIsLastCaptureFrameKM(IMG_BOOL *pbIsLastCaptureFrame)
{
	PDumpCtrlLockAcquire();
	*pbIsLastCaptureFrame = PDumpCtrlIsLastCaptureFrame();
	PDumpCtrlLockRelease();

	return PVRSRV_OK;
}



typedef struct _PDUMP_Transition_DATA_ {
	PFN_PDUMP_TRANSITION	pfnCallback;
	void					*hPrivData;
	PDUMP_CONNECTION_DATA	*psPDumpConnectionData;
	DLLIST_NODE				sNode;
} PDUMP_Transition_DATA;

PVRSRV_ERROR PDumpRegisterTransitionCallback(PDUMP_CONNECTION_DATA *psPDumpConnectionData,
											  PFN_PDUMP_TRANSITION pfnCallback,
											  void *hPrivData,
											  void **ppvHandle)
{
	PDUMP_Transition_DATA *psData;
	PVRSRV_ERROR eError;

	psData = OSAllocMem(sizeof(*psData));
	if (psData == NULL)
	{
		eError = PVRSRV_ERROR_OUT_OF_MEMORY;
		goto fail_alloc;
	}

	/* Setup the callback and add it to the list for this process */
	psData->pfnCallback = pfnCallback;
	psData->hPrivData = hPrivData;

	OSLockAcquire(psPDumpConnectionData->hLock);
	dllist_add_to_head(&psPDumpConnectionData->sListHead, &psData->sNode);
	OSLockRelease(psPDumpConnectionData->hLock);

	/* Take a reference on the connection so it doesn't get freed too early */
	psData->psPDumpConnectionData =_PDumpConnectionAcquire(psPDumpConnectionData);
	*ppvHandle = psData;

	return PVRSRV_OK;

fail_alloc:
	PVR_ASSERT(eError != PVRSRV_OK);
	return eError;
}

void PDumpUnregisterTransitionCallback(void *pvHandle)
{
	PDUMP_Transition_DATA *psData = pvHandle;

	OSLockAcquire(psData->psPDumpConnectionData->hLock);
	dllist_remove_node(&psData->sNode);
	OSLockRelease(psData->psPDumpConnectionData->hLock);
	_PDumpConnectionRelease(psData->psPDumpConnectionData);
	OSFreeMem(psData);
}

PVRSRV_ERROR PDumpTransition(PDUMP_CONNECTION_DATA *psPDumpConnectionData, IMG_BOOL bInto, IMG_UINT32 ui32PDumpFlags)
{
	DLLIST_NODE *psNode, *psNext;
	PVRSRV_ERROR eError;

	/* Only call the callbacks if we've really done a Transition */
	if (bInto != psPDumpConnectionData->bLastInto)
	{
		OSLockAcquire(psPDumpConnectionData->hLock);
		/* We're Transitioning either into or out of capture range */
		dllist_foreach_node(&psPDumpConnectionData->sListHead, psNode, psNext)
		{
			PDUMP_Transition_DATA *psData =
				IMG_CONTAINER_OF(psNode, PDUMP_Transition_DATA, sNode);

			eError = psData->pfnCallback(psData->hPrivData, bInto, ui32PDumpFlags);

			if (eError != PVRSRV_OK)
			{
				OSLockRelease(psPDumpConnectionData->hLock);
				return eError;
			}
		}
		OSLockRelease(psPDumpConnectionData->hLock);

		if (bInto)
		{
			/* Client sync prims are managed in blocks.
			 * In case of block-mode of PDump, sync-blocks will get re-dumped
			 * at start of each pdump-block after live-FW thread and app-thread gets
			 * synchronised.
			 *
			 * At playback time, we will first synchronise script-thread and sim-FW
			 * threads and then re-load sync-blocks before processing next pdump-block.
			 * */
			SyncConnectionPDumpSyncBlocks(psPDumpConnectionData->psSyncConnectionData);
		}
		psPDumpConnectionData->bLastInto = bInto;
	}
	return PVRSRV_OK;
}


PVRSRV_ERROR PDumpIsCaptureFrameKM(IMG_BOOL *bInCaptureRange)
{
	IMG_UINT64 ui64State = 0;
	PVRSRV_ERROR eError;

	eError = PDumpCtrlGetState(&ui64State);

	*bInCaptureRange = (ui64State & PDUMP_STATE_CAPTURE_FRAME) ? IMG_TRUE : IMG_FALSE;

	return eError;
}

PVRSRV_ERROR PDumpGetStateKM(IMG_UINT64 *ui64State)
{
	PVRSRV_ERROR eError;

	PDumpCtrlLockAcquire();
	eError = PDumpCtrlGetState(ui64State);
	PDumpCtrlLockRelease();

	return eError;
}

PVRSRV_ERROR PDumpGetCurrentBlockKM(IMG_UINT32 *pui32BlockNum)
{
	PDumpCtrlLockAcquire();
	*pui32BlockNum = PDumpCtrlGetBlock();
	PDumpCtrlLockRelease();

	return PVRSRV_OK;
}

PVRSRV_ERROR PDumpIsFirstFrameInBlockKM(IMG_BOOL *bIsFirstFrameInBlock)
{
	PDumpCtrlLockAcquire();
	*bIsFirstFrameInBlock = PDumpCtrlIsFirstFrameInBlock();
	PDumpCtrlLockRelease();

	return PVRSRV_OK;
}

static PVRSRV_ERROR _PDumpSetFrameKM(CONNECTION_DATA *psConnection,
                                     IMG_UINT32 ui32Frame)
{
	PDUMP_CONNECTION_DATA *psPDumpConnectionData = psConnection->psPDumpConnectionData;
	IMG_BOOL bWasInCaptureRange = IMG_FALSE;
	IMG_BOOL bIsFirstFrameInBlock = IMG_FALSE;
	IMG_BOOL bIsInCaptureRange = IMG_FALSE;
	IMG_BOOL bForceBlockTransition = IMG_FALSE; /* In block-mode this flag forces pdump-block transition if set */
	IMG_UINT32 ui32CurrentBlock = PDUMP_BLOCKNUM_INVALID;
	PVRSRV_ERROR eError;

	/*
		Note:
		As we can't test to see if the new frame will be in capture range
		before we set the frame number and we don't want to roll back the
		frame number if we fail then we have to save the "transient" data
		which decides if we're entering or exiting capture range along
		with a failure boolean so we know what's required on a retry
	*/
	if (psPDumpConnectionData->ui32LastSetFrameNumber != ui32Frame)
	{
		if(PDumpCtrlCapModIsBlkMode())
		{
			/* In block-mode of pdump, default length of first block will be PDUMP_BLOCKLEN_MIN.
			 * If asked to force first block length to full-length it will be ui32BlockLength
			 *
			 * E.g.
			 * Assume,
			 *
			 * ui32BlockLength = 20
			 * PDUMP_BLOCKLEN_MIN = 5
			 *
			 * Then different pdump blocks will have following number of frames in it:
			 *
			 * if(!PDumpCtrlIsFullLenFirstBlockSet())
			 * {
			 *		//pdump -b<block len>
			 *		block 0 -> 0...4
			 *		block 1 -> 5...19
			 *		block 2 -> 20...39
			 *		block 3 -> 40...59
			 *		...
			 * }
			 * else
			 * {
			 *		//pdump -bf<block len>
			 *		block 0 -> 0...19
			 *		block 1 -> 20...39
			 *		block 2 -> 40...59
			 *		block 3 -> 60...79
			 *		...
			 * }
			 *
			 * */

			if(!PDumpCtrlIsFullLenFirstBlockSet())
			{
				/* First pdump-block will be of PDUMP_BLOCKLEN_MIN length only if ui32BlockLength provided is greater than PDUMP_BLOCKLEN_MIN */
				bForceBlockTransition = (ui32Frame == PDUMP_BLOCKLEN_MIN) && (g_PDumpCtrl.ui32BlockLength > PDUMP_BLOCKLEN_MIN);
			}
			/* Check if we are entering in new pdump-block based on block frame length */
			bForceBlockTransition |= !(ui32Frame % g_PDumpCtrl.ui32BlockLength);

			if(bForceBlockTransition == IMG_TRUE) /* entering in new pdump-block */
			{
				IMG_UINT32 ui32PDumpFlags = PDUMP_FLAGS_CONTINUOUS | PDUMP_FLAGS_BLKDATA;

				/* Increment and set current block number */
				PDumpCtrlLockAcquire();
				/* Logic below is to handle the case where SetFrame(0) gets called twice */
				ui32CurrentBlock = (ui32Frame == 0)? 0 : (PDumpCtrlGetBlock() + 1);
				PDumpCtrlLockRelease();

				/* Add markers in script file to differentiate pdump-blocks of size ui32BlockLength */
				if(ui32CurrentBlock > 0)
				{
					/* Add pdump-block end marker */
					(void) PDumpCommentWithFlags(ui32PDumpFlags, "}PDUMP_BLOCK_END_0x%08X", ui32CurrentBlock - 1);
				}

				if(PDumpCtrlCaptureOn() && (ui32CurrentBlock > 0))
				{
					/* Split MAIN and BLK script out files on current pdump-block end */
					ui32PDumpFlags |= PDUMP_FLAGS_FORCESPLIT;
				}

				/* Add pdump-block start marker */
				(void) PDumpCommentWithFlags(ui32PDumpFlags, "PDUMP_BLOCK_START_0x%08X{", ui32CurrentBlock);

				PDumpCtrlLockAcquire();
				PDumpCtrlSetBlock(ui32CurrentBlock);
				PDumpCtrlSetFirstFrameInBlock(IMG_TRUE);
				PDumpCtrlLockRelease();

				bIsFirstFrameInBlock = IMG_TRUE;
			}
			else
			{
				/* This is NOT the first frame in current pdump-block */
				PDumpCtrlLockAcquire();
				PDumpCtrlSetFirstFrameInBlock(IMG_FALSE);
				PDumpCtrlLockRelease();
			}
		}

		(void) PDumpCommentWithFlags(PDUMP_FLAGS_CONTINUOUS, "Set pdump frame %u", ui32Frame);

		/*
			The boolean values below decide if the PDump transition
			should trigger because of the current context setting the
			frame number, hence the functions below should execute
			atomically and do not give a chance to some other context
			to transition
		*/
		PDumpCtrlLockAcquire();

		PDumpIsCaptureFrameKM(&bWasInCaptureRange);
		PDumpCtrlSetCurrentFrame(ui32Frame);
		PDumpIsCaptureFrameKM(&bIsInCaptureRange);

		PDumpCtrlLockRelease();

		psPDumpConnectionData->ui32LastSetFrameNumber = ui32Frame;

		/* Save the Transition data in case we fail the Transition */
		psPDumpConnectionData->bWasInCaptureRange = bWasInCaptureRange;
		psPDumpConnectionData->bIsInCaptureRange = bIsInCaptureRange;
	}
	else if (psPDumpConnectionData->bLastTransitionFailed)
	{
		/* Load the Transition data so we can try again */
		bWasInCaptureRange = psPDumpConnectionData->bWasInCaptureRange;
		bIsInCaptureRange = psPDumpConnectionData->bIsInCaptureRange;
	}
	else
	{
		/* New frame is the same as the last frame set and the last
		 * transition succeeded, no need to perform another transition.
		 */
		return PVRSRV_OK;
	}

	/* If this is first frame in a new pdump-block, do dummy transition-out and then transition-in */
	if(PDumpCtrlCapModIsBlkMode() && (bIsFirstFrameInBlock && (ui32CurrentBlock > 0)))
	{
		if((!psPDumpConnectionData->bLastTransitionFailed) || (bWasInCaptureRange && !bIsInCaptureRange))
		{
			/* Forced dummy transition-OUT of capture range */
			eError = PDumpTransition(psPDumpConnectionData, IMG_FALSE, PDUMP_FLAGS_NONE);
			if (eError != PVRSRV_OK)
			{
				/* Save transition data, so that we'll know we had failed transition-out while retrying */
				psPDumpConnectionData->bWasInCaptureRange = IMG_TRUE;
				psPDumpConnectionData->bIsInCaptureRange = IMG_FALSE;
				goto fail_Transition;
			}
		}

		/* Force dummy transition-IN, Save dummy transition data in case we fail the transition-IN*/
		psPDumpConnectionData->bWasInCaptureRange = bWasInCaptureRange = IMG_FALSE;
		psPDumpConnectionData->bIsInCaptureRange = bIsInCaptureRange = IMG_TRUE;
	}

	if (!bWasInCaptureRange && bIsInCaptureRange)
	{
		DEBUG_OUTFILES_COMMENT("PDump transition ENTER-begin frame %u (post)", ui32Frame);
		eError = PDumpTransition(psPDumpConnectionData, IMG_TRUE, PDUMP_FLAGS_NONE);
		DEBUG_OUTFILES_COMMENT("PDump transition ENTER-complete frame %u (post)", ui32Frame);
		if (eError != PVRSRV_OK)
		{
			goto fail_Transition;
		}
	}
	else if (bWasInCaptureRange && !bIsInCaptureRange)
	{
		DEBUG_OUTFILES_COMMENT("PDump transition EXIT-begin frame %u (post)", ui32Frame);
		eError = PDumpTransition(psPDumpConnectionData, IMG_FALSE, PDUMP_FLAGS_NONE);
		DEBUG_OUTFILES_COMMENT("PDump transition EXIT-complete frame %u (post)", ui32Frame);
		if (eError != PVRSRV_OK)
		{
			goto fail_Transition;
		}
	}
	else
	{
		/* Here both previous and current frames are in or out of range.
		 * There is no transition in this case.
		 */
	}

	psPDumpConnectionData->bLastTransitionFailed = IMG_FALSE;
	return PVRSRV_OK;

fail_Transition:
	psPDumpConnectionData->bLastTransitionFailed = IMG_TRUE;
	return eError;
}

PVRSRV_ERROR PDumpSetFrameKM(CONNECTION_DATA *psConnection,
                             PVRSRV_DEVICE_NODE * psDeviceNode,
                             IMG_UINT32 ui32Frame)
{
	PVRSRV_ERROR eError = PVRSRV_OK;

	PVR_UNREFERENCED_PARAMETER(psDeviceNode);

#if defined(PDUMP_TRACE_STATE)
	PVR_DPF((PVR_DBG_WARNING, "PDumpSetFrameKM: ui32Frame( %d )", ui32Frame));
#endif

	DEBUG_OUTFILES_COMMENT("(pre) Set pdump frame %u", ui32Frame);

	/* Setting frame-number to PDUMP_FRAME_UNSET will be treated as receiving force PDump capture STOP request in Server */
	if(ui32Frame == PDUMP_FRAME_UNSET)
	{
		eError =  _PDumpForceCaptureStopKM();
		if (eError != PVRSRV_OK)
		{
			PVR_LOG_ERROR(eError, "_PDumpForceCaptureStopKM");
		}
	}
	else
	{
		eError = _PDumpSetFrameKM(psConnection, ui32Frame);
		if ((eError != PVRSRV_OK) && (eError != PVRSRV_ERROR_RETRY))
		{
			PVR_LOG_ERROR(eError, "_PDumpSetFrameKM");
		}
	}
	DEBUG_OUTFILES_COMMENT("(post) Set pdump frame %u", ui32Frame);

	return eError;
}

PVRSRV_ERROR PDumpGetFrameKM(CONNECTION_DATA *psConnection,
                             PVRSRV_DEVICE_NODE * psDeviceNode,
                             IMG_UINT32* pui32Frame)
{
	PVRSRV_ERROR eError = PVRSRV_OK;

	PVR_UNREFERENCED_PARAMETER(psConnection);

	/*
		It may be safe to avoid acquiring this lock here as all the other calls
		which read/modify current frame will wait on the PDump Control bridge
		lock first. Also, in no way as of now, does the PDumping app modify the
		current frame through a call which acquires the global bridge lock.
		Still, as a legacy we acquire and then read.
	*/
	PDumpCtrlLockAcquire();

	*pui32Frame = PDumpCtrlGetCurrentFrame();

	PDumpCtrlLockRelease();
	return eError;
}

PVRSRV_ERROR PDumpSetDefaultCaptureParamsKM(IMG_UINT32 ui32Mode,
                                           IMG_UINT32 ui32Start,
                                           IMG_UINT32 ui32End,
                                           IMG_UINT32 ui32Interval,
                                           IMG_UINT32 ui32MaxParamFileSize)
{
	/*
		Acquire PDUMP_CTRL_STATE struct lock before modifications as a
		PDumping app may be reading the state data for some checks
	*/
	PVRSRV_ERROR eError = PVRSRV_OK;

	/* Validate parameters */
	if((ui32End < ui32Start) ||
		((ui32Mode != DEBUG_CAPMODE_FRAMED) && (ui32Mode != DEBUG_CAPMODE_CONTINUOUS) && (ui32Mode != DEBUG_CAPMODE_BLKMODE)))
	{
		eError = PVRSRV_ERROR_INVALID_PARAMS;
	}
	else if((ui32Mode == DEBUG_CAPMODE_BLKMODE) && ((ui32Interval < PDUMP_BLOCKLEN_MIN) || (ui32Interval > PDUMP_BLOCKLEN_MAX)))
	{
		/* force client to set ui32Interval (i.e. block length in block-mode) in valid range */
		eError = PVRSRV_ERROR_PDUMP_INVALID_BLOCKLEN;
	}
	else if(ui32Interval < 1)
	{
		eError = PVRSRV_ERROR_INVALID_PARAMS;
	}
	else if((ui32Mode == DEBUG_CAPMODE_BLKMODE) && (ui32End != PDUMP_FRAME_MAX))
	{
		/* force client to set ui32End to MAX value in block-mode */
		eError = PVRSRV_ERROR_INVALID_PARAMS;
	}

	if(eError != PVRSRV_OK)
	{
		PVR_LOG_ERROR(eError, "PDumpSetDefaultCaptureParamsKM");
		return eError;
	}

	if(PDumpIsDumpSuspended())
	{
		PVR_LOG(("PDump is in suspended state, need to reload the driver."));
	}

	PDumpCtrlLockAcquire();
	PDumpCtrlSetDefaultCaptureParams(ui32Mode, ui32Start, ui32End, ui32Interval);
	PDumpCtrlLockRelease();

	if (ui32MaxParamFileSize == 0)
	{
		g_PDumpParameters.ui32MaxFileSize = PRM_FILE_SIZE_MAX;
	}
	else
	{
		g_PDumpParameters.ui32MaxFileSize = ui32MaxParamFileSize;
	}
	return eError;
}


/**************************************************************************
 * Function Name  : PDumpReg32
 * Inputs         : pszPDumpDevName, Register offset, and value to write
 * Outputs        : None
 * Returns        : PVRSRV_ERROR
 * Description    : Create a PDUMP string, which represents a register write
**************************************************************************/
PVRSRV_ERROR PDumpReg32(IMG_CHAR	*pszPDumpRegName,
						IMG_UINT32	ui32Reg,
						IMG_UINT32	ui32Data,
						IMG_UINT32	ui32Flags)
{
	PVRSRV_ERROR eErr;
	PDUMP_GET_SCRIPT_STRING()

	PDUMP_LOCK();
	eErr = PDumpOSBufprintf(hScript, ui32MaxLen, "WRW :%s:0x%08X 0x%08X", pszPDumpRegName, ui32Reg, ui32Data);

	if (eErr != PVRSRV_OK)
	{
		PDUMP_UNLOCK();
		return eErr;
	}

	PDumpWriteScript(hScript, ui32Flags);
	PDUMP_UNLOCK();

	return PVRSRV_OK;
}


/**************************************************************************
 * Function Name  : PDumpReg64
 * Inputs         : pszPDumpDevName, Register offset, and value to write
 * Outputs        : None
 * Returns        : PVRSRV_ERROR
 * Description    : Create a PDUMP string, which represents a register write
**************************************************************************/
PVRSRV_ERROR PDumpReg64(IMG_CHAR	*pszPDumpRegName,
						IMG_UINT32	ui32Reg,
						IMG_UINT64	ui64Data,
						IMG_UINT32	ui32Flags)
{
	PVRSRV_ERROR eErr;
	PDUMP_GET_SCRIPT_STRING()

	PDUMP_LOCK();
	eErr = PDumpOSBufprintf(hScript, ui32MaxLen, "WRW64 :%s:0x%08X 0x%010" IMG_UINT64_FMTSPECX, pszPDumpRegName, ui32Reg, ui64Data);

	if (eErr != PVRSRV_OK)
	{
		PDUMP_UNLOCK();
		return eErr;
	}

	PDumpWriteScript(hScript, ui32Flags);
	PDUMP_UNLOCK();

	return PVRSRV_OK;
}

/**************************************************************************
 * Function Name  : PDumpRegLabelToReg64
 * Returns        : PVRSRV_ERROR
 * Description    : Create a PDUMP string, which represents a register write from a register label
**************************************************************************/
PVRSRV_ERROR PDumpRegLabelToReg64(IMG_CHAR *pszPDumpRegName,
                                  IMG_UINT32 ui32RegDst,
                                  IMG_UINT32 ui32RegSrc,
                                  IMG_UINT32 ui32Flags)
{
	PVRSRV_ERROR eErr;
	PDUMP_GET_SCRIPT_STRING()

	PDUMP_LOCK();
	eErr = PDumpOSBufprintf(hScript, ui32MaxLen, "WRW64 :%s:0x%08X :%s:0x%08X", pszPDumpRegName, ui32RegDst, pszPDumpRegName, ui32RegSrc);

	if (eErr != PVRSRV_OK)
	{
		PDUMP_UNLOCK();
		return eErr;
	}

	PDumpWriteScript(hScript, ui32Flags);
	PDUMP_UNLOCK();

	return PVRSRV_OK;

}

/**************************************************************************
 * Function Name  : PDumpRegLabelToMem32
 * Returns        : PVRSRV_ERROR
 * Description    : Create a PDUMP string, which represents a memory write from a register label
**************************************************************************/
PVRSRV_ERROR PDumpRegLabelToMem32(IMG_CHAR *pszPDumpRegName,
                                  IMG_UINT32 ui32Reg,
                                  PMR *psPMR,
                                  IMG_DEVMEM_OFFSET_T uiLogicalOffset,
                                  IMG_UINT32 ui32Flags)
{
	PVRSRV_ERROR eErr;
	IMG_CHAR aszMemspaceName[PHYSMEM_PDUMP_MEMSPACE_MAX_LENGTH];
	IMG_CHAR aszSymbolicName[PHYSMEM_PDUMP_SYMNAME_MAX_LENGTH];
	IMG_DEVMEM_OFFSET_T uiPDumpSymbolicOffset;
	IMG_DEVMEM_OFFSET_T uiNextSymName;

	PDUMP_GET_SCRIPT_STRING()

	eErr = PMR_PDumpSymbolicAddr(psPMR,
                                     uiLogicalOffset,
                                     PHYSMEM_PDUMP_MEMSPACE_MAX_LENGTH,
                                     aszMemspaceName,
                                     PHYSMEM_PDUMP_SYMNAME_MAX_LENGTH,
                                     aszSymbolicName,
                                     &uiPDumpSymbolicOffset,
                                     &uiNextSymName);

	if (eErr != PVRSRV_OK)
	{
		return eErr;
	}

	PDUMP_LOCK();
	eErr = PDumpOSBufprintf(hScript, ui32MaxLen, "WRW :%s:%s:0x%"IMG_UINT64_FMTSPECX" :%s:0x%08X",aszMemspaceName, aszSymbolicName,
							uiPDumpSymbolicOffset, pszPDumpRegName, ui32Reg);


	if (eErr != PVRSRV_OK)
	{
		PDUMP_UNLOCK();
		return eErr;
	}

	PDumpWriteScript(hScript, ui32Flags);
	PDUMP_UNLOCK();

	return PVRSRV_OK;
}

/**************************************************************************
 * Function Name  : PDumpRegLabelToMem64
 * Returns        : PVRSRV_ERROR
 * Description    : Create a PDUMP string, which represents a memory write from a register label
**************************************************************************/
PVRSRV_ERROR PDumpRegLabelToMem64(IMG_CHAR *pszPDumpRegName,
								  IMG_UINT32 ui32Reg,
								  PMR *psPMR,
								  IMG_DEVMEM_OFFSET_T uiLogicalOffset,
								  IMG_UINT32 ui32Flags)
{
	PVRSRV_ERROR eErr;
	IMG_CHAR aszMemspaceName[PHYSMEM_PDUMP_MEMSPACE_MAX_LENGTH];
	IMG_CHAR aszSymbolicName[PHYSMEM_PDUMP_SYMNAME_MAX_LENGTH];
	IMG_DEVMEM_OFFSET_T uiPDumpSymbolicOffset;
	IMG_DEVMEM_OFFSET_T uiNextSymName;

	PDUMP_GET_SCRIPT_STRING()

	eErr = PMR_PDumpSymbolicAddr(psPMR,
									 uiLogicalOffset,
									 PHYSMEM_PDUMP_MEMSPACE_MAX_LENGTH,
									 aszMemspaceName,
									 PHYSMEM_PDUMP_SYMNAME_MAX_LENGTH,
									 aszSymbolicName,
									 &uiPDumpSymbolicOffset,
									 &uiNextSymName);

	if (eErr != PVRSRV_OK)
	{
		return eErr;
	}

	PDUMP_LOCK();
	eErr = PDumpOSBufprintf(hScript, ui32MaxLen, "WRW64 :%s:%s:0x%"IMG_UINT64_FMTSPECX" :%s:0x%08X",aszMemspaceName, aszSymbolicName,
							uiPDumpSymbolicOffset, pszPDumpRegName, ui32Reg);


	if (eErr != PVRSRV_OK)
	{
		PDUMP_UNLOCK();
		return eErr;
	}


	PDumpWriteScript(hScript, ui32Flags);
	PDUMP_UNLOCK();

	return PVRSRV_OK;
}


/**************************************************************************
 * Function Name  : PDumpPhysHandleToInternalVar64
 * Returns        : PVRSRV_ERROR
 * Description    : Create a PDUMP string, which represents an internal var
                    write using a PDump pages handle
**************************************************************************/
PVRSRV_ERROR PDumpPhysHandleToInternalVar64(IMG_CHAR *pszInternalVar,
                                            IMG_HANDLE hPdumpPages,
                                            IMG_UINT32 ui32Flags)
{
	PVRSRV_ERROR eErr;
	IMG_CHAR *pszSymbolicName;

	PDUMP_GET_SCRIPT_STRING()

	eErr = PDumpGetSymbolicAddr(hPdumpPages,
	                            &pszSymbolicName);
	if (eErr != PVRSRV_OK)
	{
		return eErr;
	}

	PDUMP_LOCK();
	eErr = PDumpOSBufprintf(hScript, ui32MaxLen,
	                        "WRW %s %s:0x%llX",
	                        pszInternalVar, pszSymbolicName, 0llu);
	if (eErr != PVRSRV_OK)
	{
		PDUMP_UNLOCK();
		return eErr;
	}

	PDumpWriteScript(hScript, ui32Flags);
	PDUMP_UNLOCK();

	return PVRSRV_OK;
}

/**************************************************************************
 * Function Name  : PDumpMemLabelToInternalVar64
 * Returns        : PVRSRV_ERROR
 * Description    : Create a PDUMP string, which represents an internal var write using a memory label
**************************************************************************/
PVRSRV_ERROR PDumpMemLabelToInternalVar64(IMG_CHAR *pszInternalVar,
                                          PMR *psPMR,
                                          IMG_DEVMEM_OFFSET_T uiLogicalOffset,
                                          IMG_UINT32 ui32Flags)
{
	PVRSRV_ERROR eErr;
	IMG_CHAR aszMemspaceName[PHYSMEM_PDUMP_MEMSPACE_MAX_LENGTH];
	IMG_CHAR aszSymbolicName[PHYSMEM_PDUMP_SYMNAME_MAX_LENGTH];
	IMG_DEVMEM_OFFSET_T uiPDumpSymbolicOffset;
	IMG_DEVMEM_OFFSET_T uiNextSymName;

	PDUMP_GET_SCRIPT_STRING()

	eErr = PMR_PDumpSymbolicAddr(psPMR,
                                     uiLogicalOffset,
                                     PHYSMEM_PDUMP_MEMSPACE_MAX_LENGTH,
                                     aszMemspaceName,
                                     PHYSMEM_PDUMP_SYMNAME_MAX_LENGTH,
                                     aszSymbolicName,
                                     &uiPDumpSymbolicOffset,
                                     &uiNextSymName);


	if (eErr != PVRSRV_OK)
	{
		return eErr;
	}

	PDUMP_LOCK();
	eErr = PDumpOSBufprintf(hScript, ui32MaxLen, "WRW %s :%s:%s:0x%"IMG_UINT64_FMTSPECX, pszInternalVar,
							aszMemspaceName, aszSymbolicName, uiPDumpSymbolicOffset);


	if (eErr != PVRSRV_OK)
	{
		PDUMP_UNLOCK();
		return eErr;
	}

	PDumpWriteScript(hScript, ui32Flags);
	PDUMP_UNLOCK();

	return PVRSRV_OK;
}

/*!
******************************************************************************

 @Function	PDumpWriteRegANDValueOp

 @Description

 Emits the PDump commands for the logical OR operation
 Var <- Var OR Value

 @Return   PVRSRV_ERROR

******************************************************************************/
PVRSRV_ERROR PDumpWriteVarORValueOp	(const IMG_CHAR *pszInternalVariable,
                                         const IMG_UINT64 ui64Value,
                                         const IMG_UINT32 ui32PDumpFlags)
{
	PVRSRV_ERROR eErr;
	PDUMP_GET_SCRIPT_STRING();

	PDUMP_LOCK();
	eErr = PDumpOSBufprintf(hScript,
			ui32MaxLen,
			"OR %s %s 0x%"IMG_UINT64_FMTSPECX,
			pszInternalVariable,
			pszInternalVariable,
			ui64Value);

	if(eErr != PVRSRV_OK)
	{
		PDUMP_UNLOCK();
		return eErr;
	}

	PDumpWriteScript( hScript, ui32PDumpFlags);
	PDUMP_UNLOCK();

	return PVRSRV_OK;
}


/*******************************************************************************************************
 * Function Name  : PDumpRegLabelToInternalVar
 * Outputs        : None
 * Returns        : PVRSRV_ERROR
 * Description    : Create a PDUMP string, which writes a register label into an internal variable
********************************************************************************************************/
PVRSRV_ERROR PDumpRegLabelToInternalVar(IMG_CHAR *pszPDumpRegName,
                                        IMG_UINT32 ui32Reg,
                                        IMG_CHAR *pszInternalVar,
                                        IMG_UINT32 ui32Flags)

{
	PVRSRV_ERROR eErr;
	PDUMP_GET_SCRIPT_STRING()

	PDUMP_LOCK();
	eErr = PDumpOSBufprintf(hScript, ui32MaxLen, "WRW %s :%s:0x%08X", pszInternalVar, pszPDumpRegName, ui32Reg);

	if (eErr != PVRSRV_OK)
	{
		PDUMP_UNLOCK();
		return eErr;
	}

	PDumpWriteScript(hScript, ui32Flags);
	PDUMP_UNLOCK();

	return PVRSRV_OK;

}

/*******************************************************************************************************
 * Function Name  : PDumpInternalVarToReg32
 * Outputs        : None
 * Returns        : PVRSRV_ERROR
 * Description    : Create a PDUMP string, which represents a register write from an internal variable
********************************************************************************************************/
PVRSRV_ERROR PDumpInternalVarToReg32(IMG_CHAR *pszPDumpRegName,
                                     IMG_UINT32	ui32Reg,
                                     IMG_CHAR *pszInternalVar,
                                     IMG_UINT32	ui32Flags)
{
	PVRSRV_ERROR eErr;
	PDUMP_GET_SCRIPT_STRING()

	PDUMP_LOCK();
	eErr = PDumpOSBufprintf(hScript, ui32MaxLen, "WRW :%s:0x%08X %s", pszPDumpRegName, ui32Reg, pszInternalVar);

	if (eErr != PVRSRV_OK)
	{
		PDUMP_UNLOCK();
		return eErr;
	}

	PDumpWriteScript(hScript, ui32Flags);
	PDUMP_UNLOCK();

	return PVRSRV_OK;
}

/*******************************************************************************************************
 * Function Name  : PDumpInternalVarToReg64
 * Outputs        : None
 * Returns        : PVRSRV_ERROR
 * Description    : Create a PDUMP string, which represents a register write from an internal variable
********************************************************************************************************/
PVRSRV_ERROR PDumpInternalVarToReg64(IMG_CHAR *pszPDumpRegName,
                                     IMG_UINT32	ui32Reg,
                                     IMG_CHAR *pszInternalVar,
                                     IMG_UINT32	ui32Flags)
{
	PVRSRV_ERROR eErr;
	PDUMP_GET_SCRIPT_STRING()

	PDUMP_LOCK();
	eErr = PDumpOSBufprintf(hScript, ui32MaxLen, "WRW64 :%s:0x%08X %s", pszPDumpRegName, ui32Reg, pszInternalVar);

	if (eErr != PVRSRV_OK)
	{
		PDUMP_UNLOCK();
		return eErr;
	}

	PDumpWriteScript(hScript, ui32Flags);
	PDUMP_UNLOCK();

	return PVRSRV_OK;
}



/*******************************************************************************************************
 * Function Name  : PDumpMemLabelToMem32
 * Outputs        : None
 * Returns        : PVRSRV_ERROR
 * Description    : Create a PDUMP string, which represents a memory write from a memory label
********************************************************************************************************/
PVRSRV_ERROR PDumpMemLabelToMem32(PMR *psPMRSource,
                                  PMR *psPMRDest,
                                  IMG_DEVMEM_OFFSET_T uiLogicalOffsetSource,
                                  IMG_DEVMEM_OFFSET_T uiLogicalOffsetDest,
                                  IMG_UINT32	ui32Flags)
{
	PVRSRV_ERROR eErr;
	IMG_CHAR aszMemspaceNameSource[PHYSMEM_PDUMP_MEMSPACE_MAX_LENGTH];
	IMG_CHAR aszSymbolicNameSource[PHYSMEM_PDUMP_SYMNAME_MAX_LENGTH];
	IMG_CHAR aszMemspaceNameDest[PHYSMEM_PDUMP_MEMSPACE_MAX_LENGTH];
	IMG_CHAR aszSymbolicNameDest[PHYSMEM_PDUMP_MEMSPNAME_SYMB_ADDR_MAX_LENGTH];
	IMG_DEVMEM_OFFSET_T uiPDumpSymbolicOffsetSource;
	IMG_DEVMEM_OFFSET_T uiPDumpSymbolicOffsetDest;
	IMG_DEVMEM_OFFSET_T uiNextSymNameSource;
	IMG_DEVMEM_OFFSET_T uiNextSymNameDest;


	PDUMP_GET_SCRIPT_STRING()

	eErr = PMR_PDumpSymbolicAddr(psPMRSource,
                                     uiLogicalOffsetSource,
                                     PHYSMEM_PDUMP_MEMSPACE_MAX_LENGTH,
                                     aszMemspaceNameSource,
                                     PHYSMEM_PDUMP_SYMNAME_MAX_LENGTH,
                                     aszSymbolicNameSource,
                                     &uiPDumpSymbolicOffsetSource,
                                     &uiNextSymNameSource);

	if (eErr != PVRSRV_OK)
	{
		return eErr;
	}

	eErr = PMR_PDumpSymbolicAddr(psPMRDest,
                                     uiLogicalOffsetDest,
                                     PHYSMEM_PDUMP_MEMSPACE_MAX_LENGTH,
                                     aszMemspaceNameDest,
                                     PHYSMEM_PDUMP_SYMNAME_MAX_LENGTH,
                                     aszSymbolicNameDest,
                                     &uiPDumpSymbolicOffsetDest,
                                     &uiNextSymNameDest);


	if (eErr != PVRSRV_OK)
	{
		return eErr;
	}

	PDUMP_LOCK();
	eErr = PDumpOSBufprintf(hScript, ui32MaxLen, "WRW :%s:%s:0x%"IMG_UINT64_FMTSPECX" :%s:%s:0x%"IMG_UINT64_FMTSPECX,aszMemspaceNameDest, aszSymbolicNameDest,
							uiPDumpSymbolicOffsetDest, aszMemspaceNameSource, aszSymbolicNameSource,
							uiPDumpSymbolicOffsetSource);


	if (eErr != PVRSRV_OK)
	{
		PDUMP_UNLOCK();
		return eErr;
	}


	PDumpWriteScript(hScript, ui32Flags);
	PDUMP_UNLOCK();

	return PVRSRV_OK;
}

/*******************************************************************************************************
 * Function Name  : PDumpMemLabelToMem64
 * Outputs        : None
 * Returns        : PVRSRV_ERROR
 * Description    : Create a PDUMP string, which represents a memory write from a memory label
********************************************************************************************************/
PVRSRV_ERROR PDumpMemLabelToMem64(PMR *psPMRSource,
								  PMR *psPMRDest,
								  IMG_DEVMEM_OFFSET_T uiLogicalOffsetSource,
								  IMG_DEVMEM_OFFSET_T uiLogicalOffsetDest,
								  IMG_UINT32	ui32Flags)
{
	PVRSRV_ERROR eErr;
	IMG_CHAR aszMemspaceNameSource[PHYSMEM_PDUMP_MEMSPACE_MAX_LENGTH];
	IMG_CHAR aszSymbolicNameSource[PHYSMEM_PDUMP_SYMNAME_MAX_LENGTH];
	IMG_CHAR aszMemspaceNameDest[PHYSMEM_PDUMP_MEMSPACE_MAX_LENGTH];
	IMG_CHAR aszSymbolicNameDest[PHYSMEM_PDUMP_SYMNAME_MAX_LENGTH];
	IMG_DEVMEM_OFFSET_T uiPDumpSymbolicOffsetSource;
	IMG_DEVMEM_OFFSET_T uiPDumpSymbolicOffsetDest;
	IMG_DEVMEM_OFFSET_T uiNextSymNameSource;
	IMG_DEVMEM_OFFSET_T uiNextSymNameDest;


	PDUMP_GET_SCRIPT_STRING()

	eErr = PMR_PDumpSymbolicAddr(psPMRSource,
									 uiLogicalOffsetSource,
									 PHYSMEM_PDUMP_MEMSPACE_MAX_LENGTH,
									 aszMemspaceNameSource,
									 PHYSMEM_PDUMP_SYMNAME_MAX_LENGTH,
									 aszSymbolicNameSource,
									 &uiPDumpSymbolicOffsetSource,
									 &uiNextSymNameSource);

	if (eErr != PVRSRV_OK)
	{
		return eErr;
	}

	eErr = PMR_PDumpSymbolicAddr(psPMRDest,
									 uiLogicalOffsetDest,
									 PHYSMEM_PDUMP_MEMSPACE_MAX_LENGTH,
									 aszMemspaceNameDest,
									 PHYSMEM_PDUMP_SYMNAME_MAX_LENGTH,
									 aszSymbolicNameDest,
									 &uiPDumpSymbolicOffsetDest,
									 &uiNextSymNameDest);


	if (eErr != PVRSRV_OK)
	{
		return eErr;
	}

	PDUMP_LOCK();
	eErr = PDumpOSBufprintf(hScript, ui32MaxLen, "WRW64 :%s:%s:0x%"IMG_UINT64_FMTSPECX" :%s:%s:0x%"IMG_UINT64_FMTSPECX,aszMemspaceNameDest, aszSymbolicNameDest,
							uiPDumpSymbolicOffsetDest, aszMemspaceNameSource, aszSymbolicNameSource,
							uiPDumpSymbolicOffsetSource);


	if (eErr != PVRSRV_OK)
	{
		PDUMP_UNLOCK();
		return eErr;
	}


	PDumpWriteScript(hScript, ui32Flags);
	PDUMP_UNLOCK();

	return PVRSRV_OK;
}



/*!
******************************************************************************

 @Function	PDumpWriteVarSHRValueOp

 @Description

 Emits the PDump commands for the logical SHR operation
 Var <-  Var SHR Value

 @Return   PVRSRV_ERROR

******************************************************************************/
PVRSRV_ERROR PDumpWriteVarSHRValueOp (const IMG_CHAR *pszInternalVariable,
                                      const IMG_UINT64 ui64Value,
                                      const IMG_UINT32 ui32PDumpFlags)
{
	PVRSRV_ERROR eErr;
	PDUMP_GET_SCRIPT_STRING();

	PDUMP_LOCK();
	eErr = PDumpOSBufprintf(hScript,
			ui32MaxLen,
			"SHR %s %s 0x%"IMG_UINT64_FMTSPECX,
			pszInternalVariable,
			pszInternalVariable,
			ui64Value);

	if(eErr != PVRSRV_OK)
	{
		PDUMP_UNLOCK();
		return eErr;
	}

	PDumpWriteScript( hScript, ui32PDumpFlags);
	PDUMP_UNLOCK();

	return PVRSRV_OK;
}


/*!
******************************************************************************

 @Function	PDumpWriteRegANDValueOp

 @Description

 Emits the PDump commands for the logical AND operation
 Var <-  Var AND Value

 @Return   PVRSRV_ERROR

******************************************************************************/
PVRSRV_ERROR PDumpWriteVarANDValueOp (const IMG_CHAR *pszInternalVariable,
                                      const IMG_UINT64 ui64Value,
                                      const IMG_UINT32 ui32PDumpFlags)
{
	PVRSRV_ERROR eErr;
	PDUMP_GET_SCRIPT_STRING();

	PDUMP_LOCK();
	eErr = PDumpOSBufprintf(hScript,
			ui32MaxLen,
			"AND %s %s 0x%"IMG_UINT64_FMTSPECX,
			pszInternalVariable,
			pszInternalVariable,
			ui64Value);

	if(eErr != PVRSRV_OK)
	{
		PDUMP_UNLOCK();
		return eErr;
	}

	PDumpWriteScript( hScript, ui32PDumpFlags);
	PDUMP_UNLOCK();

	return PVRSRV_OK;
}


/**************************************************************************
 * Function Name  : PDumpSAW
 * Inputs         : pszDevSpaceName -- device space from which to output
 *                  ui32Offset -- offset value from register base
 *                  ui32NumSaveBytes -- number of bytes to output
 *                  pszOutfileName -- name of file to output to
 *                  ui32OutfileOffsetByte -- offset into output file to write
 *                  uiPDumpFlags -- flags to pass to PDumpOSWriteScript
 * Outputs        : None
 * Returns        : PVRSRV_ERROR
 * Description    : Dumps the contents of a register bank into a file
 *                  NB: ui32NumSaveBytes must be divisible by 4
**************************************************************************/
PVRSRV_ERROR PDumpSAW(IMG_CHAR      *pszDevSpaceName,
                      IMG_UINT32    ui32HPOffsetBytes,
                      IMG_UINT32    ui32NumSaveBytes,
                      IMG_CHAR      *pszOutfileName,
                      IMG_UINT32    ui32OutfileOffsetByte,
                      PDUMP_FLAGS_T uiPDumpFlags)
{
	PVRSRV_ERROR eError;

	PDUMP_GET_SCRIPT_STRING()

	PVR_DPF((PVR_DBG_ERROR, "PDumpSAW\n"));

	PDUMP_LOCK();
	eError = PDumpOSBufprintf(hScript,
	                          ui32MaxLen,
	                          "SAW :%s:0x%x 0x%x 0x%x %s\n",
	                          pszDevSpaceName,
	                          ui32HPOffsetBytes,
	                          ui32NumSaveBytes / (IMG_UINT32)sizeof(IMG_UINT32),
	                          ui32OutfileOffsetByte,
	                          pszOutfileName);

	if(eError != PVRSRV_OK)
	{
		PVR_DPF((PVR_DBG_ERROR, "PDumpSAW PDumpOSBufprintf failed: eError=%u\n", eError));
		PDUMP_UNLOCK();
		return eError;
	}

	if(! PDumpWriteScript(hScript, uiPDumpFlags))
	{
		PVR_DPF((PVR_DBG_ERROR, "PDumpSAW PDumpWriteScript failed!\n"));
	}
	PDUMP_UNLOCK();

	return PVRSRV_OK;

}


/**************************************************************************
 * Function Name  : PDumpRegPolKM
 * Inputs         : Description of what this register read is trying to do
 *					pszPDumpDevName
 *					Register offset
 *					expected value
 *					mask for that value
 * Outputs        : None
 * Returns        : None
 * Description    : Create a PDUMP string which represents a register read
 *					with the expected value
**************************************************************************/
PVRSRV_ERROR PDumpRegPolKM(IMG_CHAR				*pszPDumpRegName,
						   IMG_UINT32			ui32RegAddr,
						   IMG_UINT32			ui32RegValue,
						   IMG_UINT32			ui32Mask,
						   IMG_UINT32			ui32Flags,
						   PDUMP_POLL_OPERATOR	eOperator)
{
	/* Timings correct for linux and XP */
	/* Timings should be passed in */
	#define POLL_DELAY			1000U
	#define POLL_COUNT_LONG		(2000000000U / POLL_DELAY)
	#define POLL_COUNT_SHORT	(1000000U / POLL_DELAY)

	PVRSRV_ERROR eErr;
	IMG_UINT32	ui32PollCount;

	PDUMP_GET_SCRIPT_STRING();

	ui32PollCount = POLL_COUNT_LONG;

	PDUMP_LOCK();
	eErr = PDumpOSBufprintf(hScript, ui32MaxLen, "POL :%s:0x%08X 0x%08X 0x%08X %d %u %d",
							pszPDumpRegName, ui32RegAddr, ui32RegValue,
							ui32Mask, eOperator, ui32PollCount, POLL_DELAY);
	if(eErr != PVRSRV_OK)
	{
		PDUMP_UNLOCK();
		return eErr;
	}

	PDumpWriteScript(hScript, ui32Flags);

	PDUMP_UNLOCK();
	return PVRSRV_OK;
}

/* Never call direct, needs caller to hold OS Lock.
 * Use PDumpCommentWithFlags() from within the server.
 * Clients call this via the bridge and PDumpCommentKM().
 */
static PVRSRV_ERROR _PDumpWriteComment(IMG_CHAR *pszComment, IMG_UINT32 ui32Flags)
{
	PVRSRV_ERROR eErr;
#if defined(PDUMP_DEBUG_OUTFILES)
	IMG_CHAR pszTemp[256];
#endif
	PDUMP_GET_SCRIPT_STRING();

	if((pszComment == NULL) || (PDumpOSBuflen(pszComment, ui32MaxLen) == 0))
	{
		/* PDumpOSVerifyLineEnding silently fails if pszComment is too short to
		   actually hold the line endings that it's trying to enforce, so
		   short circuit it and force safety */
		pszComment = "\n";
	}
	else
	{
		/* Put line ending sequence at the end if it isn't already there */
		PDumpOSVerifyLineEnding(pszComment, ui32MaxLen);
	}

#if defined(PDUMP_DEBUG_OUTFILES)
	/* Prefix comment with PID and line number */
	eErr = PDumpOSSprintf(pszTemp, 256, "%u %u:%lu %s: %s",
		g_ui32EveryLineCounter,
		OSGetCurrentClientProcessIDKM(),
		(unsigned long)OSGetCurrentClientThreadIDKM(),
		OSGetCurrentClientProcessNameKM(),
		pszComment);

	/* Append the comment to the script stream */
	eErr = PDumpOSBufprintf(hScript, ui32MaxLen, "-- %s",
		pszTemp);
#else
	eErr = PDumpOSBufprintf(hScript, ui32MaxLen, "-- %s",
		pszComment);
#endif
	if( (eErr != PVRSRV_OK) &&
		(eErr != PVRSRV_ERROR_PDUMP_BUF_OVERFLOW))
	{
		PVR_LOGG_IF_ERROR(eErr, "PDumpOSBufprintf", ErrUnlock);
	}

	if (!PDumpWriteScript(hScript, ui32Flags))
	{
		if(PDUMP_IS_CONTINUOUS(ui32Flags))
		{
			eErr = PVRSRV_ERROR_PDUMP_BUFFER_FULL;
			PVR_LOGG_IF_ERROR(eErr, "PDumpWriteScript", ErrUnlock);
		}
		else
		{
			eErr = PVRSRV_ERROR_CMD_NOT_PROCESSED;
			PVR_LOGG_IF_ERROR(eErr, "PDumpWriteScript", ErrUnlock);
		}
	}

ErrUnlock:
	return eErr;
}

/**************************************************************************
 * Function Name  : PDumpCommentKM
 * Inputs         : pszComment, ui32Flags
 * Outputs        : None
 * Returns        : None
 * Description    : Dumps a pre-formatted comment, primarily called from the
 *                : bridge.
**************************************************************************/
PVRSRV_ERROR PDumpCommentKM(IMG_CHAR *pszComment, IMG_UINT32 ui32Flags)
{
	PVRSRV_ERROR eErr = PVRSRV_OK;

	PDUMP_LOCK();

	eErr =  _PDumpWriteComment(pszComment, ui32Flags);

	PDUMP_UNLOCK();
	return eErr;
}

/**************************************************************************
 * Function Name  : PDumpCommentWithFlags
 * Inputs         : psPDev - PDev for PDump device
 *				  : pszFormat - format string for comment
 *				  : ... - args for format string
 * Outputs        : None
 * Returns        : None
 * Description    : PDumps a comments
**************************************************************************/
PVRSRV_ERROR PDumpCommentWithFlags(IMG_UINT32 ui32Flags, IMG_CHAR * pszFormat, ...)
{
	PVRSRV_ERROR eErr = PVRSRV_OK;
	va_list args;

	va_start(args, pszFormat);
	PDumpCommentWithFlagsVA(ui32Flags, pszFormat, args);
	va_end(args);

	return eErr;
}

/**************************************************************************
 * Function Name  : PDumpCommentWithFlagsVA
 * Inputs         : psPDev    - PDev for PDump device
 *				  : pszFormat - format string for comment
 *				  : args      - pre-started va_list args for format string
 * Outputs        : None
 * Returns        : None
 * Description    : PDumps a comments
**************************************************************************/
PVRSRV_ERROR PDumpCommentWithFlagsVA(IMG_UINT32 ui32Flags, const IMG_CHAR * pszFormat, va_list args)
{
	PVRSRV_ERROR eErr = PVRSRV_OK;
	PDUMP_GET_MSG_STRING();

	PDUMP_LOCK();

	/* Construct the string */
	eErr = PDumpOSVSprintf(pszMsg, ui32MaxLen, pszFormat, args);

	if(eErr != PVRSRV_OK)
	{
		goto Unlock;
	}

	eErr =  _PDumpWriteComment(pszMsg, ui32Flags);

Unlock:
	PDUMP_UNLOCK();
	return eErr;
}

/*************************************************************************/ /*!
 * Function Name  : PDumpPanic
 * Inputs         : ui32PanicNo - Unique number for panic condition
 *				  : pszPanicMsg - Panic reason message limited to ~90 chars
 *				  : pszPPFunc   - Function name string where panic occurred
 *				  : ui32PPline  - Source line number where panic occurred
 * Outputs        : None
 * Returns        : PVRSRV_ERROR
 * Description    : PDumps a panic assertion. Used when the host driver
 *                : detects a condition that will lead to an invalid PDump
 *                : script that cannot be played back off-line.
 */ /*************************************************************************/
PVRSRV_ERROR PDumpPanic(IMG_UINT32      ui32PanicNo,
						IMG_CHAR*       pszPanicMsg,
						const IMG_CHAR* pszPPFunc,
						IMG_UINT32      ui32PPline)
{
	PVRSRV_ERROR   eError = PVRSRV_OK;
	PDUMP_FLAGS_T  uiPDumpFlags = PDUMP_FLAGS_CONTINUOUS;
	IMG_CHAR       pszConsoleMsg[] =
"COM ***************************************************************************\n"
"COM Script invalid and not compatible with off-line playback. Check test \n"
"COM parameters and driver configuration, stop imminent.\n"
"COM ***************************************************************************\n";
	PDUMP_GET_SCRIPT_STRING();

	/* Log the panic condition to the live kern.log in both REL and DEB mode
	 * to aid user PDump trouble shooting. */
	PVR_LOG(("PDUMP PANIC %08x: %s", ui32PanicNo, pszPanicMsg));
	PVR_DPF((PVR_DBG_MESSAGE, "PDUMP PANIC start %s:%d", pszPPFunc, ui32PPline));

	/* Check the supplied panic reason string is within length limits */
	PVR_ASSERT(OSStringLength(pszPanicMsg)+sizeof("PANIC   ") < PVRSRV_PDUMP_MAX_COMMENT_SIZE-1);

	/* Obtain lock to keep the multi-line
	 * panic statement together in a single atomic write */
	PDUMP_LOCK();


	/* Write -- Panic start (Function:line) */
	eError = PDumpOSBufprintf(hScript, ui32MaxLen, "-- Panic start (%s:%d)", pszPPFunc, ui32PPline);
	PVR_LOGG_IF_ERROR(eError, "PDumpOSBufprintf", e1);
	(void)PDumpWriteScript(hScript, uiPDumpFlags);

	/* Write COM <message> x4 */
	eError = PDumpOSBufprintf(hScript, ui32MaxLen, "%s", pszConsoleMsg);
	PVR_LOGG_IF_ERROR(eError, "PDumpOSBufprintf", e1);
	(void)PDumpWriteScript(hScript, uiPDumpFlags);

	/* Write PANIC no msg command */
	eError = PDumpOSBufprintf(hScript, ui32MaxLen, "PANIC %08x %s", ui32PanicNo, pszPanicMsg);
	PVR_LOGG_IF_ERROR(eError, "PDumpOSBufprintf", e1);
	(void)PDumpWriteScript(hScript, uiPDumpFlags);

	/* Write -- Panic end */
	eError = PDumpOSBufprintf(hScript, ui32MaxLen, "-- Panic end");
	PVR_LOGG_IF_ERROR(eError, "PDumpOSBufprintf", e1);
	(void)PDumpWriteScript(hScript, uiPDumpFlags);

e1:
	PDUMP_UNLOCK();

	return eError;
}

/*************************************************************************/ /*!
 * Function Name  : PDumpCaptureError
 * Inputs         : ui32ErrorNo - Unique number for panic condition
 *                : pszErrorMsg - Panic reason message limited to ~90 chars
 *                : pszPPFunc   - Function name string where panic occurred
 *                : ui32PPline  - Source line number where panic occurred
 * Outputs        : None
 * Returns        : PVRSRV_ERROR
 * Description    : PDumps an error string to the script file to interrupt
 *                : play back to inform user of a fatal issue that occurred
 *                : during PDump capture.
 */ /*************************************************************************/
PVRSRV_ERROR PDumpCaptureError(PVRSRV_ERROR    ui32ErrorNo,
                       IMG_CHAR*       pszErrorMsg,
                       const IMG_CHAR* pszPPFunc,
                       IMG_UINT32      ui32PPline)
{
	IMG_CHAR*       pszFormatStr = "DRIVER_ERROR: %3d: %s";
	PDUMP_FLAGS_T   uiPDumpFlags = PDUMP_FLAGS_CONTINUOUS;

	/* Need to return an error using this macro */
	PDUMP_GET_SCRIPT_STRING();

	/* Check the supplied panic reason string is within length limits */
	PVR_ASSERT(OSStringLength(pszErrorMsg)+sizeof(pszFormatStr) < PVRSRV_PDUMP_MAX_COMMENT_SIZE-1);

	/* Obtain lock to keep the multi-line
	 * panic statement together in a single atomic write */
	PDUMP_LOCK();

	/* Write driver error message to the script file */
	(void) PDumpOSBufprintf(hScript, ui32MaxLen, pszFormatStr, ui32ErrorNo, pszErrorMsg);
	(void) PDumpWriteScript(hScript, uiPDumpFlags);

	PDUMP_UNLOCK();

	return PVRSRV_OK;
}

/*!
******************************************************************************

 @Function	PDumpBitmapKM

 @Description

 Dumps a bitmap from device memory to a file

 @Input    psDevId
 @Input    pszFileName
 @Input    ui32FileOffset
 @Input    ui32Width
 @Input    ui32Height
 @Input    ui32StrideInBytes
 @Input    sDevBaseAddr
 @Input    ui32Size
 @Input    ePixelFormat
 @Input    eMemFormat
 @Input    ui32PDumpFlags

 @Return   PVRSRV_ERROR			:

******************************************************************************/
PVRSRV_ERROR PDumpBitmapKM(	PVRSRV_DEVICE_NODE *psDeviceNode,
							IMG_CHAR *pszFileName,
							IMG_UINT32 ui32FileOffset,
							IMG_UINT32 ui32Width,
							IMG_UINT32 ui32Height,
							IMG_UINT32 ui32StrideInBytes,
							IMG_DEV_VIRTADDR sDevBaseAddr,
							IMG_UINT32 ui32MMUContextID,
							IMG_UINT32 ui32Size,
							PDUMP_PIXEL_FORMAT ePixelFormat,
							IMG_UINT32 ui32AddrMode,
							IMG_UINT32 ui32PDumpFlags)
{
	PVRSRV_DEVICE_IDENTIFIER *psDevId = &psDeviceNode->sDevId;
	PVRSRV_ERROR eErr=0;
	PDUMP_GET_SCRIPT_STRING();

	PDumpCommentWithFlags(ui32PDumpFlags, "Dump bitmap of render.");

	switch (ePixelFormat)
	{
		case PVRSRV_PDUMP_PIXEL_FORMAT_YUV8:
		{
			PDumpCommentWithFlags(ui32PDumpFlags, "YUV data. Switching from SII to SAB. Width=0x%08X Height=0x%08X Stride=0x%08X",
							 						ui32Width, ui32Height, ui32StrideInBytes);
			PDUMP_LOCK();
			eErr = PDumpOSBufprintf(hScript,
									ui32MaxLen,
									"SAB :%s:v%x:0x%010"IMG_UINT64_FMTSPECX" 0x%08X 0x%08X %s.bin\n",
									psDevId->pszPDumpDevName,
									ui32MMUContextID,
									sDevBaseAddr.uiAddr,
									ui32Size,
									ui32FileOffset,
									pszFileName);

			if (eErr != PVRSRV_OK)
			{
				PDUMP_UNLOCK();
				return eErr;
			}

			PDumpWriteScript( hScript, ui32PDumpFlags);
			PDUMP_UNLOCK();
			break;
		}
		case PVRSRV_PDUMP_PIXEL_FORMAT_420PL12YUV8: // YUV420 2 planes
		{
			const IMG_UINT32 ui32Plane0Size = ui32StrideInBytes*ui32Height;
			const IMG_UINT32 ui32Plane1Size = ui32Plane0Size>>1; // YUV420
			const IMG_UINT32 ui32Plane1FileOffset = ui32FileOffset + ui32Plane0Size;
			const IMG_UINT32 ui32Plane1MemOffset = ui32Plane0Size;

			PDumpCommentWithFlags(ui32PDumpFlags, "YUV420 2-plane. Width=0x%08X Height=0x%08X Stride=0x%08X",
							 						ui32Width, ui32Height, ui32StrideInBytes);
			PDUMP_LOCK();
			eErr = PDumpOSBufprintf(hScript,
						ui32MaxLen,
						"SII %s %s.bin :%s:v%x:0x%010"IMG_UINT64_FMTSPECX" 0x%08X 0x%08X :%s:v%x:0x%010"IMG_UINT64_FMTSPECX" 0x%08X 0x%08X 0x%08X 0x%08X 0x%08X 0x%08X 0x%08X",
						pszFileName,
						pszFileName,

						// Plane 0 (Y)
						psDevId->pszPDumpDevName,	// memsp
						ui32MMUContextID,			// Context id
						sDevBaseAddr.uiAddr,		// virtaddr
						ui32Plane0Size,				// size
						ui32FileOffset,				// fileoffset

						// Plane 1 (UV)
						psDevId->pszPDumpDevName,	// memsp
						ui32MMUContextID,			// Context id
						sDevBaseAddr.uiAddr+ui32Plane1MemOffset,	// virtaddr
						ui32Plane1Size,				// size
						ui32Plane1FileOffset,		// fileoffset

						ePixelFormat,
						ui32Width,
						ui32Height,
						ui32StrideInBytes,
						ui32AddrMode);

			if (eErr != PVRSRV_OK)
			{
				PDUMP_UNLOCK();
				return eErr;
			}

			PDumpWriteScript( hScript, ui32PDumpFlags);
			PDUMP_UNLOCK();
			break;
		}

		case PVRSRV_PDUMP_PIXEL_FORMAT_YUV_YV12: // YUV420 3 planes
		{
			const IMG_UINT32 ui32Plane0Size = ui32StrideInBytes*ui32Height;
			const IMG_UINT32 ui32Plane1Size = ui32Plane0Size>>2; // YUV420
			const IMG_UINT32 ui32Plane2Size = ui32Plane1Size;
			const IMG_UINT32 ui32Plane1FileOffset = ui32FileOffset + ui32Plane0Size;
			const IMG_UINT32 ui32Plane2FileOffset = ui32Plane1FileOffset + ui32Plane1Size;
			const IMG_UINT32 ui32Plane1MemOffset = ui32Plane0Size;
			const IMG_UINT32 ui32Plane2MemOffset = ui32Plane0Size+ui32Plane1Size;

			PDumpCommentWithFlags(ui32PDumpFlags, "YUV420 3-plane. Width=0x%08X Height=0x%08X Stride=0x%08X",
							 						ui32Width, ui32Height, ui32StrideInBytes);
			PDUMP_LOCK();
			eErr = PDumpOSBufprintf(hScript,
						ui32MaxLen,
						"SII %s %s.bin :%s:v%x:0x%010"IMG_UINT64_FMTSPECX" 0x%08X 0x%08X :%s:v%x:0x%010"IMG_UINT64_FMTSPECX" 0x%08X 0x%08X :%s:v%x:0x%010"IMG_UINT64_FMTSPECX" 0x%08X 0x%08X 0x%08X 0x%08X 0x%08X 0x%08X 0x%08X",
						pszFileName,
						pszFileName,

						// Plane 0 (Y)
						psDevId->pszPDumpDevName,	// memsp
						ui32MMUContextID,			// MMU context id
						sDevBaseAddr.uiAddr,		// virtaddr
						ui32Plane0Size,				// size
						ui32FileOffset,				// fileoffset

						// Plane 1 (U)
						psDevId->pszPDumpDevName,	// memsp
						ui32MMUContextID,			// MMU context id
						sDevBaseAddr.uiAddr+ui32Plane1MemOffset,	// virtaddr
						ui32Plane1Size,				// size
						ui32Plane1FileOffset,		// fileoffset

						// Plane 2 (V)
						psDevId->pszPDumpDevName,	// memsp
						ui32MMUContextID,			// MMU context id
						sDevBaseAddr.uiAddr+ui32Plane2MemOffset,	// virtaddr
						ui32Plane2Size,				// size
						ui32Plane2FileOffset,		// fileoffset

						ePixelFormat,
						ui32Width,
						ui32Height,
						ui32StrideInBytes,
						ui32AddrMode);

			if (eErr != PVRSRV_OK)
			{
				PDUMP_UNLOCK();
				return eErr;
			}

			PDumpWriteScript( hScript, ui32PDumpFlags);
			PDUMP_UNLOCK();
			break;
		}

		case PVRSRV_PDUMP_PIXEL_FORMAT_YUV_YV32: // YV32 - 4 contiguous planes in the order VUYA, stride can be > width.
		{
			const IMG_UINT32 ui32PlaneSize = ui32StrideInBytes*ui32Height; // All 4 planes are the same size
			const IMG_UINT32 ui32Plane0FileOffset = ui32FileOffset + (ui32PlaneSize<<1);		// SII plane 0 is Y, which is YV32 plane 2
			const IMG_UINT32 ui32Plane1FileOffset = ui32FileOffset + ui32PlaneSize;				// SII plane 1 is U, which is YV32 plane 1
			const IMG_UINT32 ui32Plane2FileOffset = ui32FileOffset;								// SII plane 2 is V, which is YV32 plane 0
			const IMG_UINT32 ui32Plane3FileOffset = ui32Plane0FileOffset + ui32PlaneSize;		// SII plane 3 is A, which is YV32 plane 3
			const IMG_UINT32 ui32Plane0MemOffset = ui32PlaneSize<<1;
			const IMG_UINT32 ui32Plane1MemOffset = ui32PlaneSize;
			const IMG_UINT32 ui32Plane2MemOffset = 0;
			const IMG_UINT32 ui32Plane3MemOffset = ui32Plane0MemOffset + ui32PlaneSize;

			PDumpCommentWithFlags(ui32PDumpFlags, "YV32 4 planes. Width=0x%08X Height=0x%08X Stride=0x%08X",
							 						ui32Width, ui32Height, ui32StrideInBytes);

			PDumpCommentWithFlags(ui32PDumpFlags, "YV32 plane size is 0x%08X", ui32PlaneSize);

			PDumpCommentWithFlags(ui32PDumpFlags, "YV32 Plane 0 Mem Offset=0x%08X", ui32Plane0MemOffset);
			PDumpCommentWithFlags(ui32PDumpFlags, "YV32 Plane 1 Mem Offset=0x%08X", ui32Plane1MemOffset);
			PDumpCommentWithFlags(ui32PDumpFlags, "YV32 Plane 2 Mem Offset=0x%08X", ui32Plane2MemOffset);
			PDumpCommentWithFlags(ui32PDumpFlags, "YV32 Plane 3 Mem Offset=0x%08X", ui32Plane3MemOffset);

			/*
				SII <imageset> <filename>	:<memsp1>:v<id1>:<virtaddr1> <size1> <fileoffset1>		Y
											:<memsp2>:v<id2>:<virtaddr2> <size2> <fileoffset2>		U
											:<memsp3>:v<id3>:<virtaddr3> <size3> <fileoffset3>		V
											:<memsp4>:v<id4>:<virtaddr4> <size4> <fileoffset4>		A
											<pixfmt> <width> <height> <stride> <addrmode>
			*/
			PDUMP_LOCK();
			eErr = PDumpOSBufprintf(hScript,
						ui32MaxLen,
						"SII %s %s.bin :%s:v%x:0x%010"IMG_UINT64_FMTSPECX" 0x%08X 0x%08X :%s:v%x:0x%010"IMG_UINT64_FMTSPECX" 0x%08X 0x%08X :%s:v%x:0x%010"IMG_UINT64_FMTSPECX" 0x%08X 0x%08X :%s:v%x:0x%010"IMG_UINT64_FMTSPECX" 0x%08X 0x%08X 0x%08X 0x%08X 0x%08X 0x%08X 0x%08X",
						pszFileName,
						pszFileName,

						// Plane 0 (V)
						psDevId->pszPDumpDevName,	// memsp
						ui32MMUContextID,			// MMU context id
						sDevBaseAddr.uiAddr+ui32Plane0MemOffset,	// virtaddr
						ui32PlaneSize,				// size
						ui32Plane0FileOffset,		// fileoffset

						// Plane 1 (U)
						psDevId->pszPDumpDevName,	// memsp
						ui32MMUContextID,			// MMU context id
						sDevBaseAddr.uiAddr+ui32Plane1MemOffset,	// virtaddr
						ui32PlaneSize,				// size
						ui32Plane1FileOffset,		// fileoffset

						// Plane 2 (Y)
						psDevId->pszPDumpDevName,	// memsp
						ui32MMUContextID,			// MMU context id
						sDevBaseAddr.uiAddr+ui32Plane2MemOffset,	// virtaddr
						ui32PlaneSize,				// size
						ui32Plane2FileOffset,		// fileoffset

						// Plane 3 (A)
						psDevId->pszPDumpDevName,	// memsp
						ui32MMUContextID,			// MMU context id
						sDevBaseAddr.uiAddr+ui32Plane3MemOffset,	// virtaddr
						ui32PlaneSize,				// size
						ui32Plane3FileOffset,		// fileoffset

						ePixelFormat,
						ui32Width,
						ui32Height,
						ui32StrideInBytes,
						ui32AddrMode);

			if (eErr != PVRSRV_OK)
			{
				PDUMP_UNLOCK();
				return eErr;
			}

			PDumpWriteScript( hScript, ui32PDumpFlags);
			PDUMP_UNLOCK();
			break;
		}

		default: // Single plane formats
		{
			PDUMP_LOCK();
			eErr = PDumpOSBufprintf(hScript,
						ui32MaxLen,
						"SII %s %s.bin :%s:v%x:0x%010"IMG_UINT64_FMTSPECX" 0x%08X 0x%08X 0x%08X 0x%08X 0x%08X 0x%08X 0x%08X",
						pszFileName,
						pszFileName,
						psDevId->pszPDumpDevName,
						ui32MMUContextID,
						sDevBaseAddr.uiAddr,
						ui32Size,
						ui32FileOffset,
						ePixelFormat,
						ui32Width,
						ui32Height,
						ui32StrideInBytes,
						ui32AddrMode);

			if (eErr != PVRSRV_OK)
			{
				PDUMP_UNLOCK();
				return eErr;
			}

			PDumpWriteScript( hScript, ui32PDumpFlags);
			PDUMP_UNLOCK();
			break;
		}
	}

	return PVRSRV_OK;
}

/*!
******************************************************************************

 @Function	PDumpImageDescriptorKM

 @Description

 Dumps an OutputImage command and its associated header info.

 @Input    psDeviceNode 		: device
 @Input    ui32MMUContextID		: MMU context
 @Input    ui32Size				: size of filename string
 @Input    pszSABFileName		: filename string

 @Return   PVRSRV_ERROR			:

******************************************************************************/
PVRSRV_ERROR PDumpImageDescriptorKM(PVRSRV_DEVICE_NODE *psDeviceNode,
									IMG_UINT32 ui32MMUContextID,
									IMG_UINT32 ui32Size,
									IMG_CHAR *pszSABFileName,
									IMG_DEV_VIRTADDR sData,
									IMG_UINT32 ui32DataSize,
									IMG_UINT32 ui32LogicalWidth,
									IMG_UINT32 ui32LogicalHeight,
									IMG_UINT32 ui32PhysicalWidth,
									IMG_UINT32 ui32PhysicalHeight,
									PDUMP_PIXEL_FORMAT ePixFmt,
									IMG_MEMLAYOUT eMemLayout,
									IMG_FB_COMPRESSION eFBCompression,
									const IMG_UINT32 *paui32FBCClearColour,
									IMG_DEV_VIRTADDR sHeader,
									IMG_UINT32 ui32HeaderSize,
									IMG_UINT32 ui32PDumpFlags)
{
#if !defined(SUPPORT_RGX)
	PVR_UNREFERENCED_PARAMETER(psDeviceNode);
	PVR_UNREFERENCED_PARAMETER(ui32MMUContextID);
	PVR_UNREFERENCED_PARAMETER(ui32Size);
	PVR_UNREFERENCED_PARAMETER(pszSABFileName);
	PVR_UNREFERENCED_PARAMETER(sData);
	PVR_UNREFERENCED_PARAMETER(ui32DataSize);
	PVR_UNREFERENCED_PARAMETER(ui32LogicalWidth);
	PVR_UNREFERENCED_PARAMETER(ui32LogicalHeight);
	PVR_UNREFERENCED_PARAMETER(ui32PhysicalWidth);
	PVR_UNREFERENCED_PARAMETER(ui32PhysicalHeight);
	PVR_UNREFERENCED_PARAMETER(ePixFmt);
	PVR_UNREFERENCED_PARAMETER(eMemLayout);
	PVR_UNREFERENCED_PARAMETER(eFBCompression);
	PVR_UNREFERENCED_PARAMETER(paui32FBCClearColour);
	PVR_UNREFERENCED_PARAMETER(sHeader);
	PVR_UNREFERENCED_PARAMETER(ui32HeaderSize);
	PVR_UNREFERENCED_PARAMETER(ui32PDumpFlags);

	return PVRSRV_ERROR_NOT_IMPLEMENTED;
#else
	PVRSRV_ERROR eErr=0;
	IMG_CHAR *pszPDumpDevName = psDeviceNode->sDevId.pszPDumpDevName;
	IMG_BYTE abyPDumpDesc[IMAGE_HEADER_SIZE];
	IMG_UINT32 ui32ParamOutPos, ui32SABOffset = 0;

	PDUMP_GET_SCRIPT_AND_FILE_STRING();
	PVR_UNREFERENCED_PARAMETER(ui32MaxLenFileName);

	if (ui32PDumpFlags & PDUMP_FLAGS_PERSISTENT)
	{
		return PVRSRV_OK;
	}

	PDumpCommentWithFlags(ui32PDumpFlags, "Dump Image descriptor");

	/**
	 * Ensure string is NULL terminated.
	 */
	pszSABFileName[ui32Size-1] = '\0';

	/*
	 * Generate OutputImage command header
	 */
	eErr = RGXPDumpOutputImageHdr(	psDeviceNode,
									ui32HeaderSize,
									ui32DataSize,
									ui32LogicalWidth,
									ui32LogicalHeight,
									ui32PhysicalWidth,
									ui32PhysicalHeight,
									ePixFmt,
									eMemLayout,
									eFBCompression,
									paui32FBCClearColour,
									&(abyPDumpDesc[0]));
	if (eErr != PVRSRV_OK)
	{
		PVR_DPF((PVR_DBG_ERROR, "Failed to write image header data, error %d", eErr));
		return eErr;
	}

	PDUMP_LOCK();

	eErr = PDumpWriteParameter(abyPDumpDesc,
							   IMAGE_HEADER_SIZE,
							   ui32PDumpFlags,
							   &ui32ParamOutPos,
							   pszFileName);
	if (eErr != PVRSRV_OK)
	{
		if (eErr != PVRSRV_ERROR_PDUMP_NOT_ALLOWED)
		{
			PDUMP_ERROR(eErr, "Failed to write device allocation to parameter file");
			PVR_DPF((PVR_DBG_ERROR, "Failed to write device allocation to parameter file, error %d", eErr));
		}
		else
		{
			/*
			 * Write to parameter file prevented under the flags and
			 * current state of the driver so skip write to script and return.
			 */
			eErr = PVRSRV_OK;
		}
		goto error;
	}

	eErr = PDumpOSBufprintf(hScript,
							ui32MaxLenScript,
							"MALLOC :%s:BINHEADER 0x%08X 0x%08X\n",
							pszPDumpDevName,
							IMAGE_HEADER_SIZE,
							IMAGE_HEADER_SIZE);
	if (eErr != PVRSRV_OK)
	{
		goto error;
	}
	PDumpWriteScript(hScript, ui32PDumpFlags);

	eErr = PDumpOSBufprintf(hScript,
							ui32MaxLenScript,
							"LDB :%s:BINHEADER:0x00 0x%08x 0x%08x %s\n",
							pszPDumpDevName,
							IMAGE_HEADER_SIZE,
							ui32ParamOutPos,
							pszFileName);
	if (eErr != PVRSRV_OK)
	{
		goto error;
	}
	PDumpWriteScript(hScript, ui32PDumpFlags);

	eErr = PDumpOSBufprintf(hScript,
							ui32MaxLenScript,
							"SAB :%s:BINHEADER:0x00 0x%08X 0x00000000 %s.bin\n",
							pszPDumpDevName,
							IMAGE_HEADER_SIZE,
							pszSABFileName);
	if (eErr != PVRSRV_OK)
	{
		goto error;
	}
	PDumpWriteScript(hScript, ui32PDumpFlags);

	ui32SABOffset += IMAGE_HEADER_SIZE;

	/*
	 * Write out the header section if  image is FB compressed
	 */
	if (eFBCompression != IMG_FB_COMPRESSION_NONE)
	{
		eErr = PDumpOSBufprintf(hScript,
								ui32MaxLenScript,
								"SAB :%s:v%x:0x%010"IMG_UINT64_FMTSPECX" 0x%08X 0x%08X %s.bin\n",
								pszPDumpDevName,
								ui32MMUContextID,
								(IMG_UINT64)sHeader.uiAddr,
								ui32HeaderSize,
								ui32SABOffset,
								pszSABFileName);
		if (eErr != PVRSRV_OK)
		{
			goto error;
		}
		PDumpWriteScript(hScript, ui32PDumpFlags);

		ui32SABOffset += ui32HeaderSize;
	}

	/*
	 * Now dump out the actual data associated with the surface
	 */
	eErr = PDumpOSBufprintf(hScript,
							ui32MaxLenScript,
							"SAB :%s:v%x:0x%010"IMG_UINT64_FMTSPECX" 0x%08X 0x%08X %s.bin\n",
							pszPDumpDevName,
							ui32MMUContextID,
							(IMG_UINT64)sData.uiAddr,
							ui32DataSize,
							ui32SABOffset,
							pszSABFileName);

	if (eErr != PVRSRV_OK)
	{
		goto error;
	}
	PDumpWriteScript(hScript, ui32PDumpFlags);

	/*
	 * The OutputImage command is required to trigger processing of the output
	 * data
	 */
 	eErr = PDumpOSBufprintf(hScript,
							ui32MaxLenScript,
							"CMD:OutputImage %s.bin\n",
							pszSABFileName);
	if (eErr != PVRSRV_OK)
	{
		goto error;
	}
	PDumpWriteScript(hScript, ui32PDumpFlags);

	eErr = PDumpOSBufprintf(hScript,
							ui32MaxLenScript,
							"FREE :%s:BINHEADER\n",
							pszPDumpDevName);
	if (eErr != PVRSRV_OK)
	{
		goto error;
	}
	PDumpWriteScript(hScript, ui32PDumpFlags);

error:
	PDUMP_UNLOCK();
	return eErr;
#endif
}

/*!
******************************************************************************

 @Function	PDumpReadRegKM

 @Description

 Dumps a read from a device register to a file

 @Input    psConnection 		: connection info
 @Input    pszFileName
 @Input    ui32FileOffset
 @Input    ui32Address
 @Input    ui32Size
 @Input    ui32PDumpFlags

 @Return   PVRSRV_ERROR			:

******************************************************************************/
PVRSRV_ERROR PDumpReadRegKM		(	IMG_CHAR *pszPDumpRegName,
									IMG_CHAR *pszFileName,
									IMG_UINT32 ui32FileOffset,
									IMG_UINT32 ui32Address,
									IMG_UINT32 ui32Size,
									IMG_UINT32 ui32PDumpFlags)
{
	PVRSRV_ERROR eErr;
	PDUMP_GET_SCRIPT_STRING();

	PVR_UNREFERENCED_PARAMETER(ui32Size);

	PDUMP_LOCK();
	eErr = PDumpOSBufprintf(hScript,
			ui32MaxLen,
			"SAB :%s:0x%08X 0x%08X %s",
			pszPDumpRegName,
			ui32Address,
			ui32FileOffset,
			pszFileName);
	if(eErr != PVRSRV_OK)
	{
		PDUMP_UNLOCK();
		return eErr;
	}

	PDumpWriteScript( hScript, ui32PDumpFlags);
	PDUMP_UNLOCK();

	return PVRSRV_OK;
}

/*****************************************************************************
 @name		PDumpRegRead32
 @brief		Dump 32-bit register read to script
 @param		pszPDumpDevName - pdump device name
 @param		ui32RegOffset - register offset
 @param		ui32Flags - pdump flags
 @return	Error
*****************************************************************************/
PVRSRV_ERROR PDumpRegRead32(IMG_CHAR *pszPDumpRegName,
							const IMG_UINT32 ui32RegOffset,
							IMG_UINT32 ui32Flags)
{
	PVRSRV_ERROR eErr;
	PDUMP_GET_SCRIPT_STRING();

	PDUMP_LOCK();
	eErr = PDumpOSBufprintf(hScript, ui32MaxLen, "RDW :%s:0x%X",
							pszPDumpRegName,
							ui32RegOffset);
	if(eErr != PVRSRV_OK)
	{
		PDUMP_UNLOCK();
		return eErr;
	}
	PDumpWriteScript(hScript, ui32Flags);
	PDUMP_UNLOCK();
	return PVRSRV_OK;
}

/*****************************************************************************
 @name		PDumpRegRead64ToInternalVar
 @brief		Read 64-bit register into an internal variable
 @param		pszPDumpDevName - pdump device name
 @param		ui32RegOffset - register offset
 @param		ui32Flags - pdump flags
 @return	Error
*****************************************************************************/
PVRSRV_ERROR PDumpRegRead64ToInternalVar(IMG_CHAR *pszPDumpRegName,
                            IMG_CHAR *pszInternalVar,
							const IMG_UINT32 ui32RegOffset,
							IMG_UINT32 ui32Flags)
{
	PVRSRV_ERROR eErr;
	PDUMP_GET_SCRIPT_STRING();

	PDUMP_LOCK();
	eErr = PDumpOSBufprintf(hScript, ui32MaxLen, "RDW64 %s :%s:0x%X",
							pszInternalVar,
							pszPDumpRegName,
							ui32RegOffset);
	if(eErr != PVRSRV_OK)
	{
		PDUMP_UNLOCK();
		return eErr;
	}
	PDumpWriteScript(hScript, ui32Flags);
	PDUMP_UNLOCK();
	return PVRSRV_OK;
}
/*****************************************************************************
 @name		PDumpRegRead64
 @brief		Dump 64-bit register read to script
 @param		pszPDumpDevName - pdump device name
 @param		ui32RegOffset - register offset
 @param		ui32Flags - pdump flags
 @return	Error
*****************************************************************************/
PVRSRV_ERROR PDumpRegRead64(IMG_CHAR *pszPDumpRegName,
							const IMG_UINT32 ui32RegOffset,
							IMG_UINT32 ui32Flags)
{
	PVRSRV_ERROR eErr;
	PDUMP_GET_SCRIPT_STRING();

	PDUMP_LOCK();
	eErr = PDumpOSBufprintf(hScript, ui32MaxLen, "RDW64 :%s:0x%X",
							pszPDumpRegName,
							ui32RegOffset);
	if(eErr != PVRSRV_OK)
	{
		PDUMP_UNLOCK();
		return eErr;
	}
	PDumpWriteScript(hScript, ui32Flags);
	PDUMP_UNLOCK();
	return PVRSRV_OK;
}


/*****************************************************************************
 FUNCTION	: PDumpWriteShiftedMaskedValue

 PURPOSE	: Emits the PDump commands for writing a masked shifted address
              into another location

 PARAMETERS	: PDump symbolic name and offset of target word
              PDump symbolic name and offset of source address
              right shift amount
              left shift amount
              mask

 RETURNS	: None
*****************************************************************************/
PVRSRV_ERROR
PDumpWriteShiftedMaskedValue(const IMG_CHAR *pszDestRegspaceName,
                             const IMG_CHAR *pszDestSymbolicName,
                             IMG_DEVMEM_OFFSET_T uiDestOffset,
                             const IMG_CHAR *pszRefRegspaceName,
                             const IMG_CHAR *pszRefSymbolicName,
                             IMG_DEVMEM_OFFSET_T uiRefOffset,
                             IMG_UINT32 uiSHRAmount,
                             IMG_UINT32 uiSHLAmount,
                             IMG_UINT32 uiMask,
                             IMG_DEVMEM_SIZE_T uiWordSize,
                             IMG_UINT32 uiPDumpFlags)
{
	PVRSRV_ERROR         eError;

    /* Suffix of WRW command in PDump (i.e. WRW or WRW64) */
    const IMG_CHAR       *pszWrwSuffix;

    /* Internal PDump register used for interim calculation */
    const IMG_CHAR       *pszPDumpIntRegSpace;
    IMG_UINT32           uiPDumpIntRegNum;

	PDUMP_GET_SCRIPT_STRING();

    if ((uiWordSize != 4) && (uiWordSize != 8))
    {
        return PVRSRV_ERROR_NOT_SUPPORTED;
    }

    pszWrwSuffix = (uiWordSize == 8) ? "64" : "";

    /* Should really "Acquire" a pdump register here */
    pszPDumpIntRegSpace = pszDestRegspaceName;
    uiPDumpIntRegNum = 1;

	PDUMP_LOCK();
	eError = PDumpOSBufprintf(hScript,
                              ui32MaxLen,
                              /* Should this be "MOV" instead? */
                              "WRW :%s:$%d :%s:%s:" IMG_DEVMEM_OFFSET_FMTSPEC "\n",
                              /* dest */
                              pszPDumpIntRegSpace,
                              uiPDumpIntRegNum,
                              /* src */
                              pszRefRegspaceName,
                              pszRefSymbolicName,
                              uiRefOffset);
    if (eError != PVRSRV_OK)
    {
        goto ErrUnlock;
    }

    PDumpWriteScript(hScript, uiPDumpFlags);

    if (uiSHRAmount > 0)
    {
        eError = PDumpOSBufprintf(hScript,
                                  ui32MaxLen,
                                  "SHR :%s:$%d :%s:$%d 0x%X\n",
                                  /* dest */
                                  pszPDumpIntRegSpace,
                                  uiPDumpIntRegNum,
                                  /* src A */
                                  pszPDumpIntRegSpace,
                                  uiPDumpIntRegNum,
                                  /* src B */
                                  uiSHRAmount);
        if (eError != PVRSRV_OK)
        {
            goto ErrUnlock;
        }
        PDumpWriteScript(hScript, uiPDumpFlags);
    }

    if (uiSHLAmount > 0)
    {
        eError = PDumpOSBufprintf(hScript,
                                  ui32MaxLen,
                                  "SHL :%s:$%d :%s:$%d 0x%X\n",
                                  /* dest */
                                  pszPDumpIntRegSpace,
                                  uiPDumpIntRegNum,
                                  /* src A */
                                  pszPDumpIntRegSpace,
                                  uiPDumpIntRegNum,
                                  /* src B */
                                  uiSHLAmount);
        if (eError != PVRSRV_OK)
        {
            goto ErrUnlock;
        }
        PDumpWriteScript(hScript, uiPDumpFlags);
    }

    if (uiMask != (1ULL << (8*uiWordSize))-1)
    {
        eError = PDumpOSBufprintf(hScript,
                                  ui32MaxLen,
                                  "AND :%s:$%d :%s:$%d 0x%X\n",
                                  /* dest */
                                  pszPDumpIntRegSpace,
                                  uiPDumpIntRegNum,
                                  /* src A */
                                  pszPDumpIntRegSpace,
                                  uiPDumpIntRegNum,
                                  /* src B */
                                  uiMask);
        if (eError != PVRSRV_OK)
        {
            goto ErrUnlock;
        }
        PDumpWriteScript(hScript, uiPDumpFlags);
    }

    eError = PDumpOSBufprintf(hScript,
                              ui32MaxLen,
                              "WRW%s :%s:%s:" IMG_DEVMEM_OFFSET_FMTSPEC " :%s:$%d\n",
                              pszWrwSuffix,
                              /* dest */
                              pszDestRegspaceName,
                              pszDestSymbolicName,
                              uiDestOffset,
                              /* src */
                              pszPDumpIntRegSpace,
                              uiPDumpIntRegNum);
    if(eError != PVRSRV_OK)
    {
        goto ErrUnlock;
    }
    PDumpWriteScript(hScript, uiPDumpFlags);

ErrUnlock:
	PDUMP_UNLOCK();
	return eError;
}


PVRSRV_ERROR
PDumpWriteSymbAddress(const IMG_CHAR *pszDestSpaceName,
                      IMG_DEVMEM_OFFSET_T uiDestOffset,
                      const IMG_CHAR *pszRefSymbolicName,
                      IMG_DEVMEM_OFFSET_T uiRefOffset,
                      const IMG_CHAR *pszPDumpDevName,
                      IMG_UINT32 ui32WordSize,
                      IMG_UINT32 ui32AlignShift,
                      IMG_UINT32 ui32Shift,
                      IMG_UINT32 uiPDumpFlags)
{
    const IMG_CHAR       *pszWrwSuffix = "";
	PVRSRV_ERROR         eError = PVRSRV_OK;

	PDUMP_GET_SCRIPT_STRING();

    if (ui32WordSize == 8)
    {
        pszWrwSuffix = "64";
    }

    PDUMP_LOCK();

    if (ui32AlignShift != ui32Shift)
    {
    	/* Write physical address into a variable */
    	eError = PDumpOSBufprintf(hScript,
    							ui32MaxLen,
    							"WRW%s :%s:$1 %s:" IMG_DEVMEM_OFFSET_FMTSPEC "\n",
    							pszWrwSuffix,
    							/* dest */
    							pszPDumpDevName,
    							/* src */
    							pszRefSymbolicName,
    							uiRefOffset);
		if (eError != PVRSRV_OK)
		{
			goto symbAddress_error;
		}
    	PDumpWriteScript(hScript, uiPDumpFlags);

    	/* apply address alignment  */
    	eError = PDumpOSBufprintf(hScript,
    							ui32MaxLen,
    							"SHR :%s:$1 :%s:$1 0x%X",
    							/* dest */
    							pszPDumpDevName,
    							/* src A */
    							pszPDumpDevName,
    							/* src B */
    							ui32AlignShift);
		if (eError != PVRSRV_OK)
		{
			goto symbAddress_error;
		}
    	PDumpWriteScript(hScript, uiPDumpFlags);

    	/* apply address shift  */
    	eError = PDumpOSBufprintf(hScript,
    							ui32MaxLen,
    							"SHL :%s:$1 :%s:$1 0x%X",
    							/* dest */
    							pszPDumpDevName,
    							/* src A */
    							pszPDumpDevName,
    							/* src B */
    							ui32Shift);
		if (eError != PVRSRV_OK)
		{
			goto symbAddress_error;
		}
    	PDumpWriteScript(hScript, uiPDumpFlags);


    	/* write result to register */
    	eError = PDumpOSBufprintf(hScript,
    							ui32MaxLen,
    							"WRW%s :%s:0x%08X :%s:$1",
    							pszWrwSuffix,
    							pszDestSpaceName,
    							(IMG_UINT32)uiDestOffset,
    							pszPDumpDevName);
		if (eError != PVRSRV_OK)
		{
			goto symbAddress_error;
		}
    	PDumpWriteScript(hScript, uiPDumpFlags);
    }
    else
    {
		eError = PDumpOSBufprintf(hScript,
								  ui32MaxLen,
								  "WRW%s :%s:" IMG_DEVMEM_OFFSET_FMTSPEC " %s:" IMG_DEVMEM_OFFSET_FMTSPEC "\n",
								  pszWrwSuffix,
								  /* dest */
								  pszDestSpaceName,
								  uiDestOffset,
								  /* src */
								  pszRefSymbolicName,
								  uiRefOffset);
		if (eError != PVRSRV_OK)
		{
			goto symbAddress_error;
		}
	    PDumpWriteScript(hScript, uiPDumpFlags);
    }

symbAddress_error:

    PDUMP_UNLOCK();

	return eError;
}

/**************************************************************************
 * Function Name  : PDumpIDLWithFlags
 * Inputs         : Idle time in clocks
 * Outputs        : None
 * Returns        : Error
 * Description    : Dump IDL command to script
**************************************************************************/
PVRSRV_ERROR PDumpIDLWithFlags(IMG_UINT32 ui32Clocks, IMG_UINT32 ui32Flags)
{
	PVRSRV_ERROR eErr;
	PDUMP_GET_SCRIPT_STRING();

	PDUMP_LOCK();
	eErr = PDumpOSBufprintf(hScript, ui32MaxLen, "IDL %u", ui32Clocks);
	if(eErr != PVRSRV_OK)
	{
		PDUMP_UNLOCK();
		return eErr;
	}
	PDumpWriteScript(hScript, ui32Flags);
	PDUMP_UNLOCK();
	return PVRSRV_OK;
}


/**************************************************************************
 * Function Name  : PDumpIDL
 * Inputs         : Idle time in clocks
 * Outputs        : None
 * Returns        : Error
 * Description    : Dump IDL command to script
**************************************************************************/
PVRSRV_ERROR PDumpIDL(IMG_UINT32 ui32Clocks)
{
	return PDumpIDLWithFlags(ui32Clocks, PDUMP_FLAGS_CONTINUOUS);
}

/*****************************************************************************
 FUNCTION	: PDumpRegBasedCBP

 PURPOSE	: Dump CBP command to script

 PARAMETERS	:

 RETURNS	: None
*****************************************************************************/
PVRSRV_ERROR PDumpRegBasedCBP(IMG_CHAR		*pszPDumpRegName,
							  IMG_UINT32	ui32RegOffset,
							  IMG_UINT32	ui32WPosVal,
							  IMG_UINT32	ui32PacketSize,
							  IMG_UINT32	ui32BufferSize,
							  IMG_UINT32	ui32Flags)
{
	PVRSRV_ERROR eErr;
	PDUMP_GET_SCRIPT_STRING();

	PDUMP_LOCK();
	eErr = PDumpOSBufprintf(hScript,
			 ui32MaxLen,
			 "CBP :%s:0x%08X 0x%08X 0x%08X 0x%08X",
			 pszPDumpRegName,
			 ui32RegOffset,
			 ui32WPosVal,
			 ui32PacketSize,
			 ui32BufferSize);
	if(eErr != PVRSRV_OK)
	{
		PDUMP_UNLOCK();
		return eErr;
	}
	PDumpWriteScript(hScript, ui32Flags);
	PDUMP_UNLOCK();

	return PVRSRV_OK;
}

PVRSRV_ERROR PDumpTRG(IMG_CHAR *pszMemSpace,
                      IMG_UINT32 ui32MMUCtxID,
                      IMG_UINT32 ui32RegionID,
                      IMG_BOOL bEnable,
                      IMG_UINT64 ui64VAddr,
                      IMG_UINT64 ui64LenBytes,
                      IMG_UINT32 ui32XStride,
                      IMG_UINT32 ui32Flags)
{
	PVRSRV_ERROR eErr;
	PDUMP_GET_SCRIPT_STRING();

	PDUMP_LOCK();
	if(bEnable)
	{
		eErr = PDumpOSBufprintf(hScript, ui32MaxLen,
		                 "TRG :%s:v%u %u 0x%08"IMG_UINT64_FMTSPECX" 0x%08"IMG_UINT64_FMTSPECX" %u",
		                 pszMemSpace, ui32MMUCtxID, ui32RegionID,
		                 ui64VAddr, ui64LenBytes, ui32XStride);
	}
	else
	{
		eErr = PDumpOSBufprintf(hScript, ui32MaxLen,
		                 "TRG :%s:v%u %u",
		                 pszMemSpace, ui32MMUCtxID, ui32RegionID);

	}
	if(eErr != PVRSRV_OK)
	{
		PDUMP_UNLOCK();
		return eErr;
	}

	PDumpWriteScript(hScript, ui32Flags);
	PDUMP_UNLOCK();

	return PVRSRV_OK;
}

/**************************************************************************
 * Function Name  : PDumpConnectionNotify
 * Description    : Called by the srvcore to tell PDump core that the
 *                  PDump capture and control client has connected
 **************************************************************************/
void PDumpConnectionNotify(void)
{
	PVRSRV_DATA			*psPVRSRVData = PVRSRVGetPVRSRVData();
	PVRSRV_DEVICE_NODE	*psThis;

	/* Give PDump control a chance to end the init phase, depends on OS */
	if (!PDumpCtrlInitPhaseComplete())
	{
		PDumpStopInitPhase(IMG_TRUE, IMG_FALSE);
	}

	g_ConnectionCount++;
	PVR_LOG(("PDump has connected (%u)", g_ConnectionCount));

	/* Reset the parameter file attributes */
	g_PDumpParameters.sWOff.ui32Main = g_PDumpParameters.sWOff.ui32Init;
	g_PDumpParameters.ui32FileIdx = 0;

	g_PDumpScript.sWOff.ui32Main = g_PDumpScript.sWOff.ui32Init;
	g_PDumpScript.ui32FileIdx = 0;

	g_PDumpBlkScript.sWOff.ui32Main = g_PDumpBlkScript.sWOff.ui32Init;
	g_PDumpBlkScript.ui32FileIdx = 0;

	/* Loop over all known devices */
	psThis = psPVRSRVData->psDeviceNodeList;
	while (psThis)
	{
		if (psThis->pfnPDumpInitDevice)
		{
			/* Reset pdump according to connected device */
			psThis->pfnPDumpInitDevice(psThis);
		}
		psThis = psThis->psNext;
	}
}

/**************************************************************************
 * Function Name  : PDumpDisconnectionNotify
 * Description    : Called by the connection_server to tell PDump core that
 *                  the PDump capture and control client has disconnected
 **************************************************************************/
void PDumpDisconnectionNotify(void)
{
	PVRSRV_ERROR eErr;

	if (PDumpCtrlCaptureOn())
	{
		PVR_LOG(("PDump killed, output files may be invalid or incomplete!"));

		/* Disable capture in server, in case PDump client was killed and did
		 * not get a chance to reset the capture parameters.
		 */
		eErr = PDumpSetDefaultCaptureParamsKM( DEBUG_CAPMODE_FRAMED,
		                                       PDUMP_FRAME_UNSET, PDUMP_FRAME_UNSET, 1, 0);
		PVR_LOG_IF_ERROR(eErr, "PVRSRVPDumpSetDefaultCaptureParams");
	}
	else
	{
		PVR_LOG(("PDump disconnected"));
	}
}

/**************************************************************************
 * Function Name  : PDumpIfKM
 * Inputs         : pszPDumpCond - string for condition
 * Outputs        : None
 * Returns        : None
 * Description    : Create a PDUMP string which represents IF command
					with condition.
**************************************************************************/
PVRSRV_ERROR PDumpIfKM(IMG_CHAR		*pszPDumpCond)
{
	PVRSRV_ERROR eErr;
	PDUMP_GET_SCRIPT_STRING()

	PDUMP_LOCK();
	eErr = PDumpOSBufprintf(hScript, ui32MaxLen, "IF %s\n", pszPDumpCond);

	if (eErr != PVRSRV_OK)
	{
		PDUMP_UNLOCK();
		return eErr;
	}

	PDumpWriteScript(hScript, PDUMP_FLAGS_CONTINUOUS);
	PDUMP_UNLOCK();

	return PVRSRV_OK;
}

/**************************************************************************
 * Function Name  : PDumpElseKM
 * Inputs         : pszPDumpCond - string for condition
 * Outputs        : None
 * Returns        : None
 * Description    : Create a PDUMP string which represents ELSE command
					with condition.
**************************************************************************/
PVRSRV_ERROR PDumpElseKM(IMG_CHAR		*pszPDumpCond)
{
	PVRSRV_ERROR eErr;
	PDUMP_GET_SCRIPT_STRING()

	PDUMP_LOCK();
	eErr = PDumpOSBufprintf(hScript, ui32MaxLen, "ELSE %s\n", pszPDumpCond);

	if (eErr != PVRSRV_OK)
	{
		PDUMP_UNLOCK();
		return eErr;
	}

	PDumpWriteScript(hScript, PDUMP_FLAGS_CONTINUOUS);
	PDUMP_UNLOCK();

	return PVRSRV_OK;
}

/**************************************************************************
 * Function Name  : PDumpFiKM
 * Inputs         : pszPDumpCond - string for condition
 * Outputs        : None
 * Returns        : None
 * Description    : Create a PDUMP string which represents FI command
					with condition.
**************************************************************************/
PVRSRV_ERROR PDumpFiKM(IMG_CHAR		*pszPDumpCond)
{
	PVRSRV_ERROR eErr;
	PDUMP_GET_SCRIPT_STRING()

	PDUMP_LOCK();
	eErr = PDumpOSBufprintf(hScript, ui32MaxLen, "FI %s\n", pszPDumpCond);

	if (eErr != PVRSRV_OK)
	{
		PDUMP_UNLOCK();
		return eErr;
	}

	PDumpWriteScript(hScript, PDUMP_FLAGS_CONTINUOUS);
	PDUMP_UNLOCK();

	return PVRSRV_OK;
}

PVRSRV_ERROR PDumpCreateLockKM(void)
{
	return PDumpOSCreateLock();
}

void PDumpDestroyLockKM(void)
{
	PDumpOSDestroyLock();
}

void PDumpLock(void)
{
	PDumpOSLock();
}

void PDumpUnlock(void)
{
	PDumpOSUnlock();
}

#if defined(PVR_TESTING_UTILS)
extern void PDumpOSDumpState(void);

#if !defined(LINUX)
void PDumpOSDumpState(IMG_BOOL bDumpOSLayerState)
{
	PVR_UNREFERENCED_PARAMETER(bDumpOSLayerState);
}
#endif

void PDumpCommonDumpState(IMG_BOOL bDumpOSLayerState)
{
	PVR_LOG(("--- PDUMP COMMON: g_PDumpInitialised( %d )",
			g_PDumpInitialised) );
	PVR_LOG(("--- PDUMP COMMON: g_PDumpScript.sCh.hInit( %p ) g_PDumpScript.sCh.hMain( %p ) g_PDumpScript.sCh.hDeinit( %p )",
			g_PDumpScript.sCh.hInit, g_PDumpScript.sCh.hMain, g_PDumpScript.sCh.hDeinit) );
	PVR_LOG(("--- PDUMP COMMON: g_PDumpParameters.sCh.hInit( %p ) g_PDumpParameters.sCh.hMain( %p ) g_PDumpParameters.sCh.hDeinit( %p )",
			g_PDumpParameters.sCh.hInit, g_PDumpParameters.sCh.hMain, g_PDumpParameters.sCh.hDeinit) );
	PVR_LOG(("--- PDUMP COMMON: g_PDumpParameters.sWOff.ui32Init( %d ) g_PDumpParameters.sWOff.ui32Main( %d ) g_PDumpParameters.sWOff.ui32Deinit( %d )",
			g_PDumpParameters.sWOff.ui32Init, g_PDumpParameters.sWOff.ui32Main, g_PDumpParameters.sWOff.ui32Deinit) );
	PVR_LOG(("--- PDUMP COMMON: g_PDumpParameters.ui32FileIdx( %d )",
			g_PDumpParameters.ui32FileIdx) );

	PVR_LOG(("--- PDUMP COMMON: g_PDumpCtrl( %p ) bInitPhaseActive( %d ) ui32Flags( %x )",
			&g_PDumpCtrl, g_PDumpCtrl.bInitPhaseActive, g_PDumpCtrl.ui32Flags) );
	PVR_LOG(("--- PDUMP COMMON: ui32DefaultCapMode( %d ) ui32CurrentFrame( %d )",
			g_PDumpCtrl.ui32DefaultCapMode, g_PDumpCtrl.ui32CurrentFrame) );
	PVR_LOG(("--- PDUMP COMMON: sCaptureRange.ui32Start( %x ) sCaptureRange.ui32End( %x ) sCaptureRange.ui32Interval( %u )",
			g_PDumpCtrl.sCaptureRange.ui32Start, g_PDumpCtrl.sCaptureRange.ui32End, g_PDumpCtrl.sCaptureRange.ui32Interval) );
	PVR_LOG(("--- PDUMP COMMON: bCaptureOn( %d ) bSuspended( %d ) bInPowerTransition( %d )",
			g_PDumpCtrl.bCaptureOn, g_PDumpCtrl.bSuspended, g_PDumpCtrl.bInPowerTransition) );

	if (bDumpOSLayerState)
	{
		PDumpOSDumpState();
	}
}
#endif


PVRSRV_ERROR PDumpRegisterConnection(SYNC_CONNECTION_DATA *psSyncConnectionData,
									 PDUMP_CONNECTION_DATA **ppsPDumpConnectionData)
{
	PDUMP_CONNECTION_DATA *psPDumpConnectionData;
	PVRSRV_ERROR eError;

	PVR_ASSERT(ppsPDumpConnectionData != NULL);

	psPDumpConnectionData = OSAllocMem(sizeof(*psPDumpConnectionData));
	if (psPDumpConnectionData == NULL)
	{
		eError = PVRSRV_ERROR_OUT_OF_MEMORY;
		goto fail_alloc;
	}

	eError = OSLockCreate(&psPDumpConnectionData->hLock);
	if (eError != PVRSRV_OK)
	{
		goto fail_lockcreate;
	}

	dllist_init(&psPDumpConnectionData->sListHead);
	OSAtomicWrite(&psPDumpConnectionData->sRefCount, 1);
	psPDumpConnectionData->bLastInto = IMG_FALSE;
	psPDumpConnectionData->ui32LastSetFrameNumber = PDUMP_FRAME_UNSET;
	psPDumpConnectionData->bLastTransitionFailed = IMG_FALSE;

	/*
	 * Although we don't take a ref count here, handle base destruction
	 * will ensure that any resource that might trigger us to do a
	 * Transition will have been freed before the sync blocks which
	 * are keeping the sync connection data alive.
	 */
	psPDumpConnectionData->psSyncConnectionData = psSyncConnectionData;
	*ppsPDumpConnectionData = psPDumpConnectionData;

	return PVRSRV_OK;

fail_lockcreate:
	OSFreeMem(psPDumpConnectionData);
fail_alloc:
	PVR_ASSERT(eError != PVRSRV_OK);
	return eError;
}

void PDumpUnregisterConnection(PDUMP_CONNECTION_DATA *psPDumpConnectionData)
{
	_PDumpConnectionRelease(psPDumpConnectionData);
}

#else	/* defined(PDUMP) */
/* disable warning about empty module */
#ifdef	_WIN32
#pragma warning (disable:4206)
#endif
#endif	/* defined(PDUMP) */
/*****************************************************************************
 End of file (pdump_common.c)
*****************************************************************************/
